轨道
/
Elm
Elm
/
练习
/
请出示车票!
请出示车票!

请出示车票!

学习练习

简介

模式匹配

模式匹配让分支代码更有表现力,解构则能把值优雅地绑定到变量上。

简单的模式匹配

借助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

说明

你是 IT 服务台的一员,你想改进工单系统,让它更高效,并为你的经理提供统计数据。

一张工单有一个状态(new、in progress……),有一个创建者(由用户名和员工编号标识),可以分配给某位 IT 员工,并包含评论历史。

下面有四个任务,它们能改进你当前的工单系统。

1. 检测空评论

空评论会让界面变得杂乱,又不提供任何信息,你想把它们过滤掉。

定义一个辅助函数emptyComment,它接收一个用户/评论对,并对空评论返回True。

直接在函数参数中使用解构来提取用户和评论。用不到用户信息,可以忽略它。

emptyComment ( User "Alice", "" )
-- => True

2. 统计创建者发表的评论数

你的经理想要了解用户在工单流程中参与情况的统计数据。 她让你查看工单创建者添加了多少条评论。

定义numberOfCreatorComments,它接收一张工单,并返回工单创建者添加的评论数。

在函数参数中使用解构,从Ticket类型中提取记录,同时提取你需要的字段。 然后,在let绑定中对createdBy进行解构,这样你就能统计相关评论了。 使用List函数来完成计数,并在匿名函数的参数中使用解构,把用户/评论对分开。

numberOfCreatorComments
numberOfCreatorComments
    (Ticket
        { status = Closed
        , createdBy = ( User "Chiaki", 1 )
        , assignedTo = Nothing
        , comments = [ ( User "Chiaki", "Never mind, fixed it." ) ]
        }
    )
-- => 1

3. 检测分配给开发团队的工单

有些工单必须上报给开发团队的 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

4. 把工单分配给 IT 员工

有时一批工单需要重新分配给其他 IT 员工。

定义一个函数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!!" ) ]
--        }
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Elm Exercism

准备好开始 请出示车票! 了吗?

注册 Exercism,借助 28 个概念110 个练习 和真人导师指导,学习并掌握 Elm,全部免费。