۱۳ - ۳کار با یه پروژه‌ی پایه

یادگیریِ Cabal و Stack رو با ساخت ِ یه پروژه‌ی نمونه به اسمِ ‏‎hello‎‏ شروع می‌کنیم. برای اینکه حجمِ کارمون رو کَم کنیم، با ‏‎git‎‏ پروژه‌ی نمونه رو ‏‎clone‎‏ می‌کنیم. به آدرسی که پروژه‌هاتون رو ذخیره می‌کنین برین و آدرسِ مخزن ِ ‏‎https://github.com/haskellbook/hello‎‏ رو ‏‎git clone‎‏ کنین.

ساخت ِ پروژه

برین به پوشه‌ای که دستورِ ‏‎git clone‎‏ درست کرد.

$ cd hello

می‌تونین فایلِ ‏‎hello.cabal‎‏ رو ویرایش کنین. مثلاً می‌تونین بجای ‏‎“Your Name Here”‎‏ اسم‌تون رو بنویسین. بعدش پروژه رو بسازین:

$ stack build

اگه گیر داد که GHC باید نصب شده باشه، نترسین! یکی از مزایای Stack اینه که می‌تونه GHC هم براتون مدیریت کنه. قبل از اینکه دوباره ‏‎stack build‎‏ رو امتحان کنین، این کار رو بکنین:

$ stack setup

دستور ‏‎setup‎‏ برای Stack، براساس اسنپ‌شات ِ LTS که در فایلِ ‏‎stack.yaml‎‏ ِ پروژه‌تون تعیین شده، نسخه‌ی GHC ِ موردِ نیازتون رو تشخیص میده. فایلِ ‏‎stack.yaml‎‏ برای تشخیصِ نسخه‌ی پکیج‌ها و پیدا کردنِ نسخه‌ای از GHC که اونها بهتر باهاش کار می‌کنن استفاده میشه. اگه این کار لازم‌تون نشد، احتمالاً نسخه‌ی GHC که داشتین سازگار بوده، یا شاید ‏‎setup‎‏ رو قبلاً برای یه اسنپ‌شات ِ LTS ِ دیگه که همین نسخه‌ی GHC رو لازم داشته اجرا کرده بودین. از سایتِ Stackage می‌تونین بیشتر یاد بگیرین.

بارگذاری و اجرای کُد از REPL

بعد از کارهای بالا، REPL رو اجرا می‌کنیم.

$ stack ghci
[... یه کم سروصدا ...]
Ok, modules loaded: Main.
Prelude> :l Main
[1 of 1] Compiling Main
Ok, modules loaded: Main.
Preldue> main
hello world

اینجا با موفقیت GHCi REPL رو (واقف به پروژه‌مون) شروع کردیم، ماژول ِ ‏‎Main‎‏ رو بارگذاری کردیم، و بعد هم تابعِ ‏‎main‎‏ رو اجرا کردیم. استفاده از GHCi ِ داخلِ Stack برای شروعِ یه REPL، نه تنها امکانِ کار با کُد‌های پروژه‌مون رو میده، بلکه امکانِ استفاده از وابستگی‌‌های پروژه‌مون رو هم فراهم می‌کنه. این رو بعداً بیشتر نشون میدیم.

‏‎stack exec‎‏

بالاتر که دستورِ ‏‎build‎‏ رو اجرا کردین، شاید چنین چیزی رو هم دیدین:

Linking .stack-work/dist/{...شلوغی...}/hello

این رو Stack موقعِ کامپایل کردنِ پروژه به یه باینریِ اجراشدنی و اتصال به اون میگه. برای اجرای اون فایلِ باینری می‌تونین کُلِ آدرس‌ش که Stack گفت رو وارد کنین، اما راه ساده‌تر هم داره – ‏‎exec‎‏! این دستورها رو از داخل پوشه‌ی پروژه‌مون وارد کردیم:

$ hello
zsh: command not found: hello
$ stack exec -- hello
hello world

Stack جای همه برنامه‌های اجراشدنی رو می‌دونه، پس با دستورِ ‏‎exec‎‏ از Stack لازم نیست کُلِ آدرسِ یه برنامه رو وارد کنین.

پاراگراف‌های executable در فایل‌های Cabal

بالاتر، Stack به خاطرِ این پاراگراف از فایلِ ‏‎hello.cabal‎‏ یه اجراشدنی درست کرد:

executable hello
--         [1]
  hs-source-dirs:      src
--   [2]
  main-is:             Main.hs
--   [3]
  default-language:    Haskell2010
--   [4]
  build-depends:       base >= 4.7 && < 5
--   [5]

۱.

این اسمی که بعد از تعریفِ یه پاراگراف ِ ‏‎executable‎‏ اومده، به Stack یا Cabal میگه که چه اسمی برای باینری یا اجراشدنی ای که درست می‌کنه بذاره.

۲.

به این پاراگراف میگه که کجا دنبالِ کُدِ منبع بِگَرده – در این مورد، زیرپوشه ِ ‏‎src‎‏.

۳.

اجرا ِ این باینری، اول از هر کاری دنبال یه تابعِ ‏‎main‎‏ داخل یه فایل به اسمِ ‏‎Main‎‏ با اسمِ ماژول ِ ‏‎Main‎‏ می‌گرده. دقت کنین که اسمِ ماژول‌ها و فایل‌ها باید یکی باشن. کامپایلری که استفاده می‌کنین (نه فقط Stack) فایلی که ماژول ِ ‏‎Main‎‏ نیست رو به عنوان نقطه‌ی شروعِ اجرایِ برنامه نمی‌پذیره. به این هم توجه داشته باشین که همه‌ی آدرس‌هایی که در ‏‎hs-source-dirs‎‏ نوشتین رو، به دنبالِ ‏‎Main.hs‎‏ می‌گَرده. اینجا فقط یه آدرس نوشتیم، پس ‏‎src/Main.hs‎‏ رو پیدا می‌کنه که تنها فایل منبع ِمون ِه.

۴.

نسخه‌ای از استانداردِ هسکل که باید انتظار داشته باشه رو تعیین می‌کنه. نه جالبه، نه کارِ زیادی می‌کنه – بیشتر تکرارنوشت* ِه، اما واجبه.

*

م. لغت boilerplate در علم کامپیوتر برای قطعاتی از نوشته که همیشه لازم هستن و تغییری هم نمی‌کنن به کار میره. تکرارنوشت پیشنهاد بنده به عنوان لغت معادل‌ه.

۵.

این معمولاً بخشِ جوندارتر از هر پاراگراف ِ Cabal ِه (بین پاراگرافهای ‏‎executable‎‏، ‏‎library‎‏، و ‏‎test-suite‎‏). این مثال (‏‎base‎‏) واقعاً حداقلِ وابستگی تو هر پروژه‌ی هسکل‌ه، بدونِ کتابخونه ِ ‏‎base‎‏ تقریباً هیچ کاری نمیشه کرد. بعداً اضافه و نصب کردن وابستگی‌های بیشتر رو نشون میدیم.

یه نکته در مورد اجراشدنی‌ها و کتابخونه‌ها

پروژه‌ی ما فقط شاملِ یه پاراگراف ِ ‏‎executable‎‏ ِه، که برای یه برنامه‌ای که فقط در ترمینال اجرا و استفاده میشه (command-line application) کفایت می‌کنه. زمان‌هایی که کُدِ ما قراره برای پروژه‌های بقیه هم قابل استفاده باشه، باید در یه پاراگراف ِ ‏‎library‎‏ داخلِ فایلِ ‏‎.cabal‎‏ مشخص کنیم که می‌خوایم کدوم ماژولها افشا بشن. اجراشدنی‌ها، برنامه‌هایی هستن که سیستم عامل مستقیماً اجراشون می‌کنه، اما کتابخونه‌ها کُدهایی هستن که کامپایلر برای ساخت ِ سایرِ کتابخونه‌ها و برنامه‌ها ازشون استفاده می‌کنه.