Julia برنامهنویسان را تشویق میکند تا جای ممکن کد را داخل توابعی بگذارند که میتوان آنها را بهصورت JIT کامپایل کرد، و ساختن تعداد زیادی تابع کوچک، طبق طراحی، کارآمد است.
نتیجهی این کار معمولاً انبوهی از توابع کوچک و ساده است که برای انجام کارهای غیرساده باید با هم ترکیب شوند.
یک راه واضح این است که فراخوانی توابع را تودرتو کنیم. مثال زیر خیلی ساختگی است، اما نکته را نشان میدهد.
julia> first.(titlecase.(reverse.(["my", "test", "strings"])))
3-element Vector{Char}:
'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)
این روش یک اشکال دارد: هرچه تودرتویی عمیقتر شود، خوانایی بهسرعت افت میکند.
به روشی سادهتر و انعطافپذیرتر نیاز داریم.
این همان تکنیکی است که ریاضیدانان دوستش دارند و Julia شکل نوشتار ریاضی آن را کپی کرده است.
میتوان هر تعداد دلخواهی از توابع را با عملگرهای ∘ composed کرد (برای وارد کردن این عملگر، \circ را تایپ کنید و بعد کلید تب را بزنید).
نتیجه را میتوان بهعنوان یک تابع واحد به کار برد.
julia> compfunc = first ∘ titlecase ∘ reverse
first ∘ titlecase ∘ reverse
julia> compfunc.(["my", "test", "strings"])
3-element Vector{Char}:
'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)
# alternative syntax, giving the same result
julia> (first ∘ titlecase ∘ reverse).(["my", "test", "strings"])
چند نکته که بهتر است به آنها توجه کنید:
راه جایگزین را میتوان رویکرد برنامهنویسان دانست، نه ریاضیدانان.
Pipelines از دیرباز در اسکریپتهای شل یونیکس به کار میرفتهاند و بهتازگی در زبانهای برنامهنویسی جریان اصلی محبوب شدهاند (گاهی پیشگامی در رواج آنها را به F# نسبت میدهند).
ایدهی اصلی این است که با مقداری داده شروع میکنید، بعد آن را از میان زنجیرهای از توابع عبور میدهید تا نتیجه به دست بیاید.
عملگر پایپ |> است (همانطور که در F# و نسخههای اخیر R هست)، هرچند Julia نسخهی پخشی .|> را هم دارد.
julia> ["my", "test", "strings"] .|> reverse .|> titlecase .|> first
3-element Vector{Char}:
'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)
اجرا حالا دقیقاً از چپ به راست است و خروجی هر تابع در جهت فلش پیش میرود تا ورودی تابع بعدی شود.
تصادفی نیست که همهی توابعی که برای نشان دادن ترکیب و پایپلاین به کار رفتند، تنها یک آرگومان میگیرند.
برخی زبانهای کاملاً تابعی، آرگومان اول را به تابع میفرستند اما اجازه میدهند آرگومانهای دیگری هم همراه باشند.
در مقابل، Julia در یک پایپلاین تنها اسم توابع (یا چیزی معادل آن) را انتظار دارد، بدون هیچ آرگومان اضافهای.
دلایل فنی مهمی برای این کار وجود دارد (مربوط به این واقعیت که currying بخشی استاندارد از طراحی زبان نیست).
بسیاری از کسانی که هیچ درکی از currying ندارند، فقط باید بپذیرند که این محدودیت یک سهو و بیدقتی نیست و احتمالاً در نسخههای آیندهی Julia تغییر نخواهد کرد.
به توابعی نیاز داریم که تنها یک آرگومان بگیرند و هر کاری که لازم است انجام دهند. خوشبختانه، تعریف توابع تازه در Julia آسان است.
سادهترین راه این است که از یک anonymous function استفاده کنیم.
برای مثال، اگر یک رشتهی ورودی داشته باشیم و بخواهیم آن را بر اساس زیرخطها تقسیم کنیم:
julia> "my_test_strings" |> (s -> split(s, '_'))
3-element Vector{SubString{String}}:
"my"
"test"
"strings"
آن بردار را میتوان بعداً مثل قبل به توابع دیگر پایپ کرد.
در این حالت، گذاشتن تابع بینام داخل پرانتز اختیاری است، اما در حالت کلی راه مفیدی برای کم کردن ابهام است.
به همین ترتیب، میتوانیم یک تابع بانام را زودتر در برنامه بسازیم و هر وقت لازم شد دوباره از آن استفاده کنیم.
در این تمرین، قرار است به عاشقهای دوران دبیرستان کمک کنید تا عشقشان را در شبکههای اجتماعی با ساختن یک قلب یونیکد از حروف اول اسمشان اعلام کنند:
❤ J. + M. ❤
متد cleanupname را پیادهسازی کنید.
این متد یک اسم میگیرد و همهی کاراکترهای - را از آن حذف میکند و با یک فاصله جایگزین میکند.
همچنین باید فاصلههای اضافی را از ابتدا و انتهای اسم حذف کند.
julia> cleanupname("Jane-Ann")
"Jane Ann"
متد firstletter را پیادهسازی کنید.
این متد یک اسم میگیرد و حرف اول آن را بهصورت یک رشته برمیگرداند.
حتماً از cleanupname که در گام قبلی تعریف کردید دوباره استفاده کنید و آن را با توابع دیگر ترکیب کنید.
julia> firstletter("Jane")
"J"
متد initial را پیادهسازی کنید.
این متد یک اسم میگیرد و حرف اول آن را با حروف بزرگ، بههمراه یک نقطه برمیگرداند.
حتماً از firstletter که در گام قبلی تعریف کردید دوباره استفاده کنید.
initial("Robert")
"R."
متد couple را پیادهسازی کنید.
این متد دو اسم میگیرد و حروف اختصاری را با قلبهای ایموجی در اطرافشان برمیگرداند.
حتماً از initial که در گام قبلی تعریف کردید دوباره استفاده کنید.
couple("Blake Miller", "Riley Lewis")
"❤ B. + R. ❤"