Shi*_*z.M 8 haskell functional-programming pattern-matching
所以我一直忙于真实世界Haskell书,我做了lastButOne练习.我想出了两个解决方案,一个是模式匹配
lastButOne :: [a] -> a
lastButOne ([]) = error "Empty List"
lastButOne (x:[]) = error "Only one element"
lastButOne (x:[x2]) = x
lastButOne (x:xs) = lastButOne xs
Run Code Online (Sandbox Code Playgroud)
一个使用案例表达
lastButOneCase :: [a] -> a
lastButOneCase x =
case x of
[] -> error "Empty List"
(x:[]) -> error "Only One Element"
(x:[x2]) -> x
(x:xs) -> lastButOneCase xs
Run Code Online (Sandbox Code Playgroud)
我想知道的是模式匹配何时优先于case表达式,反之亦然.这个例子对我来说不够好,因为看起来虽然两个函数都按预期工作,但它并没有让我选择一个实现而不是另一个.所以选择"看起来"优先乍一看?
那么有没有通过源代码获得好的案例,无论是在haskell自己的源代码还是github或其他地方,哪里可以看到哪种方法是首选的?
Dan*_*ner 15
首先是一个简短的术语转移:我会称之为"模式匹配".我不确定是否有一个很好的术语来区分模式匹配 - 通过案例和模式匹配 - 通过多重定义.
两者之间的技术区别确实很轻.您可以通过要求GHC使用-ddump-simpl标志转储为两个函数生成的核心来自行验证.我在几个不同的优化级别尝试了这一点,并且在所有情况下,核心的唯一差异是命名.(顺便说一下,如果有人知道Core的一个好的"语义差异"程序 - 它至少知道alpha等价 - 我很有兴趣听到它!)
不过,有一些小问题需要注意.您可能想知道以下内容是否也是等效的:
{-# LANGUAGE LambdaCase #-}
lastButOne = \case
[] -> error "Empty List"
(x:[]) -> error "Only One Element"
(x:[x2]) -> x
(x:xs) -> lastButOneCase xs
Run Code Online (Sandbox Code Playgroud)
在这种情况下,答案是肯定的.但请考虑这个看起来相似的一个:
-- ambiguous type error
sort = \case
[] -> []
x:xs -> insert x (sort xs)
Run Code Online (Sandbox Code Playgroud)
突然间,这是一个类型类多态CAF,所以在旧的GHC上,这将触发单态限制并导致错误,而具有显式参数的表面相同的版本不会:
-- this is fine!
sort [] = []
sort (x:xs) = insert x (sort xs)
Run Code Online (Sandbox Code Playgroud)
另一个微小的区别(我忘记了 - 感谢Thomas DuBuisson提醒我)是在处理where子句.由于where子句附加到绑定站点,因此它们不能跨多个方程共享,但可以跨多个案例共享.例如:
-- error; the where clause attaches to the second equation, so
-- empty is not in scope in the first equation
null [] = empty
null (x:xs) = nonempty
where empty = True
nonempty = False
-- ok; the where clause attaches to the equation, so both empty
-- and nonempty are in scope for the entire case expression
null x = case x of
[] -> empty
x:xs -> nonempty
where
empty = True
nonempty = False
Run Code Online (Sandbox Code Playgroud)
您可能认为这意味着您可以使用不能用case表达式执行的方程式执行某些操作,即在两个方程中对同一名称具有不同的含义,如下所示:
null [] = answer where answer = True
null (x:xs) = answer where answer = False
Run Code Online (Sandbox Code Playgroud)
但是,由于case表达式的模式是绑定站点,因此也可以在case表达式中进行模拟:
null x = case x of
[] -> answer where answer = True
x:xs -> answer where answer = False
Run Code Online (Sandbox Code Playgroud)
当然,where条款是附加到case模式还是等式取决于缩进.