تطبیق الگو نوشتن کد شاخهبندیِ گویا را ممکن میکند و ساختارشکنی اتصالی زیبا میان مقادیر و متغیرها برقرار میکند.
تطبیق الگو میتواند مقادیر را به متغیرها متصل کند، یا با «جانگهدار» _ آنها را نادیده بگیرد؛ این کار با استفاده از دستور case انجام میشود.
type Entity = Alien | Stranger (Maybe String) | Friend { name: String }
hello : Entity -> String
hello entity =
case entity of
-- Custom type variant
Alien -> "Hello, you are not from around here are you?"
-- Binding to a litteral value nested in Stranger
Stranger (Just nametag) -> "Hello, erm... " ++ nametag ++ "."
-- Discarding Friend's data
Friend _ -> "Hi!"
-- All other cases
_ -> "Hello stranger!"
ساختارشکنی میتواند مقادیر را در اتصالهای let، در آرگومانهای تابع، و البته در عبارتهای case متصل کند، هر زمان که داده فقط یک شکل ممکن داشته باشد.
pairSum : ( Int, Int ) -> Int
pairSum pair =
-- Destructuring of a pair in a 'let' binding
let ( x, y ) = pair
in x + y
-- Destructuring in the function argument
pairSum : ( Int, Int ) -> Int
pairSum ( x, y ) = x + y
-- Custom type containing a single variant
type Container = Box String
-- Destructuring in the function argument
unbox : Container -> String
unbox (Box str) = str
-- Destructuring combined with pattern matching
unboxMaybe : Maybe Container -> Maybe String
unboxMaybe maybeContainer =
case maybeContainer of
Nothing -> Nothing
Just (Box "42") -> Just "The answer to the universe!"
Just (Box str) -> Just str
از ساختارشکنی میتوان برای رکوردها هم استفاده کرد، یا همراه با کلیدواژهی as.
type alias Circle =
{ radius : Float
, center : ( Float, Float )
}
perimeter : Circle -> Float
perimeter { radius } =
2 * pi * radius
left : Circle -> Float
left { radius, center } =
-- the pair center cannot be pattern matched directly in the function argument
-- so we do it in a 'let' statement
let ( x, _ ) = center
in x - radius
-- using the 'as' keyword to bind both the fields and the whole record
smaller : Float -> Circle -> Circle
smaller reduction ({ radius } as circle) =
if reduction < radius then
{ circle | radius = radius - reduction }
else
circle
شما بخشی از میز پشتیبانی فناوری اطلاعات هستید و میخواهید سیستم تیکت را کارآمدتر کنید و برای مدیرتان آمار تهیه کنید.
هر تیکت یک وضعیت دارد (تازه، در حال انجام و...)، یک سازنده (که با یک اسم کاربری و یک شناسهی کارمند مشخص میشود)، میتواند به یکی از کارمندان فناوری اطلاعات واگذار شود و تاریخچهای از نظرها را در خود دارد.
چهار کار زیر سیستم تیکت کنونیتان را بهتر میکند.
نظرهای خالی رابط کاربری را شلوغ میکنند و هیچ اطلاعاتی به همراه ندارند؛ میخواهید آنها را حذف کنید.
یک تابع کمکی به اسم emptyComment تعریف کنید که یک جفت کاربر/نظر میگیرد و برای نظرهای خالی True برمیگرداند.
برای بیرون کشیدن کاربر و نظر، مستقیماً از «ساختارشکنی» در آرگومان تابع استفاده کنید. چون به آن اطلاعات نیازی ندارید، کاربر را نادیده بگیرید.
emptyComment ( User "Alice", "" )
-- => True
مدیرتان میخواهد دربارهی میزان مشارکت کاربران در فرایند تیکت آمار داشته باشد. او از شما میخواهد بررسی کنید که سازندهی تیکت چند نظر ثبت کرده است.
تابعی به اسم numberOfCreatorComments تعریف کنید که یک تیکت میگیرد و تعداد نظرهایی را که سازندهی تیکت اضافه کرده برمیگرداند.
با ساختارشکنی در آرگومان تابع، رکورد را از نوع Ticket بیرون بکشید و همزمان فیلدهایی را که از رکورد لازم دارید نیز استخراج کنید.
سپس createdBy را در یک اتصال let ساختارشکنی کنید تا بتوانید نظرهای مرتبط را بشمارید.
برای شمردن از توابع List استفاده کنید و برای جدا کردن جفت کاربر/نظر، در آرگومان تابع یک تابع بینام ساختارشکنی به کار ببرید.
numberOfCreatorComments
numberOfCreatorComments
(Ticket
{ status = Closed
, createdBy = ( User "Chiaki", 1 )
, assignedTo = Nothing
, comments = [ ( User "Chiaki", "Never mind, fixed it." ) ]
}
)
-- => 1
بعضی تیکتها باید به Alice، Bob یا Charlie از تیم توسعه ارجاع داده شوند. مهم است که حواستان به آنها باشد تا مطمئن شوید در حال پیشرفت هستند.
یک تابع کمکی به اسم assignedToDevTeam تعریف کنید که بررسی میکند آیا تیکت به یکی از اعضای تیم توسعه واگذار شده است یا نه.
با ساختارشکنی در آرگومان تابع، رکورد را از نوع Ticket و همچنین فیلد موردنیازتان بیرون بکشید.
سپس با یک دستور case بررسی کنید که تیکت به Alice، Bob یا Charlie واگذار شده است یا نه؛ برای بیرون کشیدن اسمهای کاربری آنها از تطبیق الگوی بازگشتی و برای مطابقت دادنشان از تطبیق الگوی تحتاللفظی استفاده کنید.
assignedToDevTeam
(Ticket
{ status = InProgress
, createdBy = ( User "Bill", 2 )
, assignedTo = Just (User "Alice")
, comments = [ ( User "Bill", "What's an 'undefined'?" ) ]
}
)
-- => True
گاهی لازم است شماری از تیکتها به کارمندان دیگری از فناوری اطلاعات دوباره واگذار شوند.
برای این کار تابعی به اسم assignTicketTo تعریف کنید. این تابع دو آرگومان میگیرد: کاربری که باید تیکت به او واگذار شود و یک تیکت.
اگر وضعیت تیکت New باشد، آن را به کاربر جدید واگذار کنید و وضعیتش را به InProgress تغییر دهید.
برای بقیهی وضعیتها، تیکت را فقط به کاربران جدید دوباره واگذار کنید؛ بهجز تیکتهایی با وضعیت Archived که نباید اصلاً تغییری در آنها داده شود.
با ساختارشکنی در آرگومان تابع، رکورد را از نوع Ticket و همچنین فیلد موردنیازتان بیرون بکشید و از کلیدواژهی as هم استفاده کنید تا کل رکورد را همانطور که هست نگه دارید.
با یک دستور case وضعیت را تطبیق الگو کنید و تیکت مناسب را برگردانید؛ تیکتی که از تغییر دادن رکورد اصلی نگهداشتهشده با کلیدواژهی as ساخته میشود.
assignTicketTo (User "Danny")
(Ticket
{ status = New
, createdBy = ( User "Jesse", 3 )
, assignedTo = Just (User "Alice")
, comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
}
)
-- => Ticket
-- { status = InProgress
-- , createdBy = ( User "Jesse", 3 )
-- , assignedTo = Just (User "Danny")
-- , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
-- }