我对haskell很新,但幸运的是我需要实现一些功能。 我对以下功能有疑问
next :: Eq a => [a] -> a -> a
next l@(x:_) e = case dropWhile (/= e) l of
(_:y:_) -> y
_ -> x
l@
做什么?dropWhile (/= e) l of
代表什么,尤其是/=
运算符of
在这种情况下的含义是什么?(_:y:_)
做什么?我知道(x:xs)
会让你抓住头部或尾部,但y
变量中的内容是什么?_ -> x
答案 0 :(得分:13)
所有好问题!
l@
做什么?
这称为 as-pattern 。它给出了整个模式的名称。 l@(x:_)
是一种匹配具有至少一个元素的列表的模式。它将列表的头部命名为x
,丢弃列表的尾部,并命名整个列表(即表达式x:_
)l
的值。
dropWhile (/= e) l of
代表什么,尤其是/=
运算符
/=
是Haskell如何拼写“不相等”。它与例如Java中的!=
相同。语法(/= e)
,其中中缀运算符在括号中给出一个参数,称为 section 。它代表(\x -> x /= e)
。因此,dropWhile (/= e) l
会删除l
中的元素,只要它们不等于e
。
of
在这种情况下的含义是什么?
它只是case
表达式语法的一部分。它将scrutinee与树枝分开:
case foo of
bar -> ...
baz -> ...
...
(_:y:_)
做什么?我知道(x:xs)
会让你抓住头部或尾部,但y
变量中的内容是什么?
这只是一个更复杂的模式。在这个例子中,它匹配列表至少包含两个元素,并命名第二个元素y
。
x:xs
将头部与尾巴分开; x:(y:ys)
将前两个元素与其余元素分开。由于(:)
是右关联的,因此您可以删除括号(x:y:ys
),而_
只是表示“我对此不感兴趣”。
- 箭头会做什么?
_ -> x
同样,它只是case
表达式语法的一部分。它将模式与返回值分开。在这种情况下,模式是一个包罗万象的通配符模式,返回值为x
。
总结一下:这个函数应该在e
中查找l
并返回以下元素。也就是说,这并不是一个特别伟大的实现。我侦察了两个特别的问题。
[]
的声明中没有next
个案的子句。 next
是部分功能。dropWhile (/= e) l
未返回包含至少两个元素的列表(以便_:y:_
模式不匹配),则它将返回x
,即列表。 (如果列表中缺少e
或者它是最后一个元素,可能会发生这种情况。)这似乎是一件非常奇怪的事情。我可能会通过考虑甚至可能没有next
l
元素的可能性来解决这个问题。 e
可能是l
的最后一个元素,或者根本不在l
。这是此函数含义的基本部分,而不仅仅是实现中的错误,因此我们应该在类型中考虑它。
next :: Eq a => [a] -> a -> Maybe a
通过向next
提供Maybe a
的返回类型,我表示它可能不会返回任何内容。
next l e = case dropWhile (/= e) l of
(_:x:_) -> Just x
_ -> Nothing
所以这个实现说:如果dropWhile (/= e) l
返回至少两个元素的列表,则返回第二个元素。 (我正在使用Just :: a -> Maybe a
将值包装到Maybe
中。)否则返回Nothing
。
不要过于担心这一点,但是对于它的价值,我们可以使用Haskell的一个更高级的功能使这个功能略微缩短。 ViewPatterns
语言扩展旨在简化此类功能,仅对次要值执行case
分析。
{-# LANGUAGE ViewPatterns #-}
next :: Eq a => a -> [a] -> Maybe a -- I've flipped the arguments
next e (dropWhile (/= e) -> _:x:_) = Just x
next _ _ = Nothing