۱۳ - ۶توضیحات بیشتر از واردات ماژولها
وارد کردنِ ماژولها، توابعِ بیشتری، به غیر از اونهایی که در Prelude ِ استاندار هستن رو واردِ گستره میکنه. ماژولهای وارد شده در واقع تعاریفِ سطح بالا اند. همهی چیزهایی هم که وارد شدن، مثل بقیهی انقیادهای سطح بالا در گستره ِ تمامِ ماژول هستن، اما ممکنه توسطِ انقیادهای محلی تیره بشن. نوشتنِ چند تعریفِ وارات اثرِ افزایشی داره، اما ترتیبِ تعریفهای وارداتی بیاهمیت ِه. اگه چیزی توسطِ هر کدوم از تعریفهای وارداتی وارد شده باشه، در گستره ِ تمامِ ماژول قرار میگیره.
در فصلهای قبل برای تمرینها توابعی مثل bool و toUpper رو با وارد کردنِ ماژولهاشون (به ترتیب Data.Bool و Data.Char) به داخلِ گستره آوردیم.
یه دوره کنیم ببینیم این کار رو چطور در GHCi انجام میدادیم. با استفاده از دستورِ :browse میشه توابعِ موجود در یه ماژولِ اسمدار رو نگاه کرد، اما با وارد کردنِ یه ماژول میشه از توابعش استفاده کرد. مرور کردنِ ماژولهایی که هنوز وارد نشدن به دردِ وقتهایی میخوره که نمیدونیم تابعِ مورد نظرمون تو کدوم ماژول ِه:
Prelude> :browse Data.Bool
bool :: a -> a -> Bool -> a
(&&) :: Bool -> Bool -> Bool
data Bool = False | True
not :: Bool -> Bool
otherwise :: Bool
(||) :: Bool -> Bool -> Bool
Prelude> import Data.Bool
Prelude> :t bool
bool :: a -> a -> Bool -> aدر مثالِ بالا، به طورِ مقیدنشده همه چیز در Data.Bool رو وارد کردیم. اگه فقط bool از Data.Bool رو لازم داشتیم چطور؟
اول Prelude رو خاموش میکنیم تا هیچ کدوم از وارداتِ پیشفرض رو نداشته باشیم. برای این کار، موقعِ اجرای GHCi از یه توسعه ِ دیگه استفاده میکنیم. قبلاً طریقهی استفاده از توسعهها در فایلها رو دیدین، اما اینجا همزمان با ورود به REPL، توسعه ِ -XNoImplicitPrelude رو وارد میکنیم:
-- این کار رو خارج از
-- هر پروژهای انجام بدین
$ stack ghci –ghci-options -XNoImplicitPrelude
Prelude>میشه ببینیم که bool و not دیگه در گستره نیستن:
Prelude> :t bool
<interactive>:1:1: Not in scope: ‘bool’
Prelude> :t not
<interactive>:1:1: Not in scope: ‘not’بعد Data.Bool رو گزینشی وارد میکنیم، یعنی مشخص میکنیم که فقط میخوایم bool رو وارد کنیم:
Prelude> import Data.Bool (bool)
Prelude> :t bool
bool :: a -> a -> Bool -> a
Prelude> :t not
<interactive>:1:1: Not in scope: ‘not’در Prelude به طور معمول not در گستره هست، اما bool نیست. پس میبینید که با خاموش کردنِ Prelude و خارج کردنِ توابعِ استانداردش از گستره، و بعد وارد کردنِ bool به تنهایی، دیگه تابعِ استانداردِ not رو در گستره نداریم.
میشه یک یا بیشترِ تابعهای یه ماژول یا کتابخونه رو وارد کرد. گرامر ِش همونطوره که با GHCi نشون دادیم، فقط تعریفهای وارداتی باید اولِ ماژول بیان. نوشتنِ import Data.Char (toUpper) در یه ماژول، باعث میشه تابعِ toUpper، و نه هیچ چیزِ دیگه از Data.Char واردِ گستره ِ اون ماژول بشه.
برای مثالهای پیشِ رو Prelude لازمه، پس لطفاً اول GHCi رو دوباره اجرا کنین.
وارداتِ مقیّد
اگه بخوایم بدونیم یه چیزی که وارد کردیم از کجا اومده چی کار کنیم؟ میشه از وارداتِ مقیّد استفاده کنیم تا اسمها صریحتر بشن.
برای این کار از کلیدواژه ِ qualified در واردات استفاده میکنیم. گاهی پیش میاد چیزهای همنامی رو از ماژولهای مختلف لازم دارین؛ مقیّد کردنِ واردات از چارههای رایج برای چنین مشکلیه. با یه مثال نشون میدیم:
Prelude> import qualified Data.Bool
Prelude> :t bool
<interactive>:1:1:
Not in scope: ‘bool’
Perhaps you meant ‘Data.Bool.bool’
Prelude> :t Data.Bool.bool
Data.Bool.bool :: a -> a -> Bool -> a
Prelude> :t Data.Bool.not
Data.Bool.not :: Bool -> Boolدر این مثال همه چیز از Data.Bool واردِ گستره شده، اما فقط به همراهِ اسمِ ماژول ِشون قابلِ دسترسیاند. با این کار دیگه مشخصه که هر تابع از کجا اومده، که گاهی به درد میخوره.
وقتهایی که واردات ِمون رو مقیّد میکنیم، امکان انتساب یه مترادف یا مستعار هم برای اونها وجود داره تا مجبور نباشیم کلِ اسمِ ماژول رو تایپ کنیم:
Prelude> import qualified Data.Bool as B
Prelude> :t bool
<interactive>:1:1:
Not in scope: ‘bool’
Perhapse you meant ‘B.bool’
Prelude> :t B.bool
B. bool :: a -> a -> Bool -> a
Prelude> :t B.not
B.not :: Bool -> Boolبرای فایلها هم به همین طریق (فقط باید اولِ ماژول نوشته بشن).
تعیینِ prompt
در مثالِ بالا وقتی Data.Bool رو به عنوانِ B وارد کردین، ممکنه متوجه شده باشین که prompt ِتون تغییر کرد:
Prelude> import qualified Data.Bool as B
Prelude B>و اگه همهی ماژولهایی که وارد کردین رو لازم داشته باشین و نخواین تخلیهشون کنین، prompt ِتون میتونه همینطور رشد کنه:
Prelude B> import Data.Char
Prelude B Data.Char>(یادآوری: میشه با دستورِ :m ماژولها رو تخلیه کرد و جلوی رشدِ prompt رو گرفت... البته این کار ماژولها رو هم از گستره خارج میکنه!)
اگه بخواین جلوی این رشدِ بیرَویهی prompt رو بگیرین، میتونین با دستورِ :set، prompt ِتون رو به هر چیز که دوست دارین تغییر بدین:
Prelude B> :set prompt "Lambda> "
Lambda> import Data.Char
Lambda> :t B.bool
B.bool :: a -> a -> Bool -> aبا اینکه Data.Bool با نامِ B هنوز در گستره هست، ولی دیگه در prompt نیست. اگه بخواین prompt رو دائماً تغییر بدین، باید دستور :set رو در فایلِ تنظیمات ِ GHCi بنویسین. توضیحِ کاملِ این کار خارج از حوزهی این فصله.
آنتراکت: ادراکتون رو چک کنید
این لیستِ واردات از یکی از ماژولها در کتابخونه ِ کریس به اسمِ blacktip آورده شده:
import qualified Control.Concurrent
as CC
import qualified Control.Concurrent.MVar
as MV
import qualified Data.ByteString.Char8
as B
import qualified Data.Locator
as DL
import qualified Data.Time.Clock.POSIX
as PSX
import qualified Filesystem
as FS
import qualified Filesystem.Path.CurrentOS
as FPC
import qualified Network.Info
as NI
import qualified Safe
import Control.Exception (mask, try)
import Control.Monad (forever, when)
import Data.Bits
import Data.Bits.Bitwise (fromListBE)
import Data.List.Split (chunksOf)
import Database.Blacktip.Types
import System.IO.Unsafe (unsafePerformIO)الان کاری نداریم که آیا این ماژولها رو میشناسین یا نه. فقط واردات رو نگاه کنین و به سؤالهای زیر جواب بدین:
۱.
از Control.Monad چه تابعهایی وارد شدن؟
۲.
کدوم ماژولها، هم مقیدنشده، و هم تماماً وارد شدن؟
۳.
فقط از روی اسم، فکر میکنین Types از ماژول ِ blacktip چه چیزهایی رو میاره؟
۴.
حالا یه بخشِ کوچیک از کُدِ blacktip رو با لیستِ بالا مقایسه کنیم:
writeTimestamp :: MV.MVar ServerState
-> FPC.FilePath
-> IO CC.ThreadId
writeTimestamp s path = do
CC.forkIO go
where go = forever $ do
ss <- MV.readMVar s
mask $ \_ -> do
FS.writeFile path
(B.pack (show (ssTime ss)))
-- sleep for 1 second
CC.threadDelay 1000000a)
تایپ سیگنچر به سه تا واردات مستعار اشاره کرده. اونها استعار از کدوم ماژولها هستن؟
b)
تابعِ FS.writeFile به کدوم واردات اشاره داره؟
c)
forever از کدوم واردات اومده؟