۱۳ - ۱۰قدم اول: وارد کردن ماژولها
-- 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
بعداً از این برای ایجاد یه اندیس ِ تصادفی که بتونیم باهاش از لیستِ لغاتمون یه کلمه رو برداریم استفاده میکنیم.