۱۳ - ۶توضیحات بیشتر از واردات ماژولها
وارد کردنِ ماژولها، توابعِ بیشتری، به غیر از اونهایی که در 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 1000000
a)
تایپ سیگنچر به سه تا واردات مستعار اشاره کرده. اونها استعار از کدوم ماژولها هستن؟
b)
تابعِ FS.writeFile
به کدوم واردات اشاره داره؟
c)
forever
از کدوم واردات اومده؟