۱۳ - ۱۰قدم اول: وارد کردن ماژولها
-- src/Main.hs
module Main where
import Control.Monad (forever) -- [1]
import Data.Char (toLower) -- [2]
import Data.Maybe (isJust) -- [3]
import Data.List (intersperse) -- [4]
import System.Exit (exitSuccess) -- [5]
import System.Random (randomRIO) -- [6]هر کدوم از واردات رو عددگذاری کردیم. شما لازم نیست اون کامنتهای عددی رو بنویسین. همهی ماژولهایی که این زیر لیست کردیم، بخشی از کتابخونه ِ base که همراه با GHC نصب میشه هستن، مگر غیرش رو گفته باشیم.
۱.
تابعِ forever از ماژول ِ Control.Monad رو برای ایجاد یه حلقهی بینهایت استفاده میکنیم. دو تا نکته:
a)
برای این کار forever واجب نیست، اما ما ازش استفاده میکنیم.
b)
انتظار نمیره که بفهمین دقیقاً چطور یا چه کاری انجام میده. اساساً بجای اینکه یک بار یه تابع محاسبه بشه، میذاره اون تابع رو بینهایت بار اجرا کنیم، تا وقتی کاری کنیم برنامه خارج بشه یا شکست بخوره.
۲.
تابعِ toLower از ماژول ِ Data.Char رو برای تبدیلِ تمام حروفِ نوشتهمون به حروف کوچک استفاده میکنیم:
λ> import Data.Char (toLower)
λ> toLower 'A'
'a'حواستون باشه که اگه حرفی معادل کوچکی نداره، toLower همون حرف رو برمیگردونه:
λ> toLower ':'
':'۳.
تابعِ isJust از ماژول ِ Data.Maybe رو برای تشخیص اینکه آیا همهی حرفهای لغتِ موردِ نظر پیدا شده یا نه استفاده میکنیم:
λ> import Data.Maybe (isJust)
λ> isJust Nothing
False
λ> isJust (Just 10)
Trueاین تابع رو با all (یکی از توابع استانداردِ Prelude) استفاده میکنیم. کارِ این تابع رو میشه اینطور توصیف کرد: "با فرض تابعی که به ازای هر المان، True یا False برمیگردونه، آیا برای همهی اون المانها True برمیگردونه؟"
λ> all even [2, 4, 6]
True
λ> all even [2, 4, 7]
False
λ> all isJust [Just 'd', Nothing, Just 'g']
False
λ> all isJust [Just 'd',Just 'o',Just 'g']
Trueتایپِ تابعِ all از این قراره:
Foldable t => (a -> Bool) -> t a -> Boolهنوز تایپکلاسِ Foldable رو توضیح ندادیم. برای فعلاً میتونین Foldable رو مجموعهای از عملیات برای تایپهایی که قابلیتِ فولد شدن (به نحوی مشابه لیستها) رو دارن فرض کنین، اما اصلاً واجب نیست مثل لیستها یا نوعدادههای مشابه، بیشتر از یک مقدار داشته باشن (یا ممکنه اصلاً هیچ مقداری نداشته باشن). با یه تایپ سیگنچر میشه تایپش رو مشخصتر کرد:
λ> :t all :: (a -> Bool) -> [a] -> Bool
all :: (a -> Bool) -> [a] -> Boolاین برای هر تایپی که یه نمونه از تایپکلاسِ Foldable داره کار میکنه:
λ> :t all :: (a -> Bool) -> Maybe a -> Bool
all :: (a -> Bool) -> Maybe a -> Bool
-- به ترتیب متغیرهای تایپ دقت کنین
-- خودتون جداگانه امتحان کنین
λ> :t all :: (a -> Bool) -> Either b a -> Bool
all :: (a -> Bool) -> Either b a -> Boolاما اگه نوعداده، نمونه از Foldable نداشته باشه کار نمیکنه:
> :t all :: (a -> Bool) -> (b -> a) -> Bool
o instance for (Foldable ((->) b1)) arising
rom a use of ‘all’
n the expression:
all :: (a -> Bool) -> (b -> a) -> Bool۴.
تابعِ intersperse از ماژول ِ Data.List رو برای میانپاشی ِ المانهای لیست استفاده میکنیم. اینجا میخوایم بین حروفی که بازیکن حدس زده فاصله بذاریم. شاید یادتون باشه که در فصلِ توابعِ بازگشتی از intersperse برای گذاشتنِ خط فاصله استفاده کردیم (در تمرینی که میخواستیم اعداد رو به لغات تبدیل کنیم):
Prelude> import Data.List (intersperse)
Prelude> intersperse ' ' "Blah"
"B l a h"تایپِ intersperse محدود به استفاده برای حرفها و نوشتهها نیست، پس میشه برای لیستهای حاوی المانهای با تایپهای گوناگون هم ازش استفاده کرد:
Prelude> :t intersperse
intersperse :: a -> [a] -> [a]
Prelude> intersperse 0 [1, 1, 1]
[1,0,1,0,1]۵.
تابعِ exitSuccess از ماژول ِ System.Exit رو برای خروج ِ موفقیتآمیز استفاده میکنیم – یعنی خطایی نیست و فقط کارمون تموم شده. اینکه موفقیتآمیز بوده یا نه رو تعیین میکنیم تا اگه خطایی اتفاق افتاده بود، سیستم عامل بدونه. دقت کنین که اگه exitSuccess رو در REPL حساب کنین، استثنا میده. تو یه برنامهی معمولی که استثنا رو نمیگیره، فقط کلِ برنامه رو تموم میکنه.
۶.
تابعِ randomRIO از ماژول ِ System.Random رو برای انتخاب تصادفی ِ لغت از دیکشنریمون استفاده میکنیم. ماژول ِ System.Random از کتابخونه ِ random ِه. باز هم باید کتابخونه رو در گستره داشته باشین تا REPL بتونه بارگذاریش کنه. همین که بیاد در گستره، میشه با randomRIO یه عددِ تصادفی بگیریم. از تایپ سیگنچر ِش میتونین ببینین که آرگومانِ ورودیش یه توپل ِه. این توپل در واقع بازهایه که از داخلِ اون یکی رو به طورِ تصادفی انتخاب میکنه:
Prelude> import System.Random
Prelude System.Random> :t randomRIO
randomRIO :: Random a => (a, a) -> IO a
Prelude System.Random> randomRIO (0, 5)
4
Prelude System.Random> randomRIO (1, 100)
71
Prelude System.Random> randomRIO (1, 100)
12بعداً از این برای ایجاد یه اندیس ِ تصادفی که بتونیم باهاش از لیستِ لغاتمون یه کلمه رو برداریم استفاده میکنیم.