我是Haskell
的新手,并且对模式匹配和元组感到困惑。例如,在Learn You a Haskell for Great Good!中:
您还可以使用绑定到模式匹配的位置!我们可以将前一个函数的where部分重写为:
...
where bmi = weight / height ^ 2
(skinny, normal, fat) = (18.5, 25.0, 30.0)
(skinny, normal, fat) = (18.5, 25.0, 30.0)
是一种模式匹配,但它也是一个元组,对吧?我如何理解和区分模式匹配和元组?
答案 0 :(得分:2)
模式匹配用于命名以特定模式设置的变量。
在这里,您可以说“变量skinny
normal
和fat
代表元组的值,它等于(18.5, 25.0, 30.0)
”
您可以在其他情况下使用模式匹配,例如列表。
first_element [] = error "Empty list"
first_element (x:rest) = x
此处的模式是空列表[]
或值x
,后跟给定列表的其余部分。
如果您输入GHCI
let (x:xs) = [2, 3, 4]
然后,模式匹配x
的值为2
,xs的值为[3, 4]
。
元组只是“盒子”,可以包含多种类型的多个值。
点可以表示为(Double, Double)
类型的元组。
您可以构造任何类型的任何元组。在您的示例中,(18.5, 25.0, 30.0)
可能属于(Double, Double, Double)
答案 1 :(得分:1)
在Haskell中,模式和表达式在很大程度上共享相同的内部语法,区别在于它们出现的位置。所以在你的例子中:
where bmi = weight / height ^ 2
(skinny, normal, fat) = (18.5, 25.0, 30.0)
... (skinny, normal, fat)
是一种模式,因为它出现在等号的左侧上,(18.5, 25.0, 30.0)
是一个表达式,因为它是一个表达式在等号的右侧。
在Haskell中有一个明确的上下文列表,其中允许使用模式,因此模式是出现在这些上下文中的事物。第一个上下文:定义方程的左侧。这可以是顶级定义,也可以是where
或let
内的本地定义:
-- Top level definition
(pat1, pat2) = ...
where
-- Local definition in `where`
(pat3:pat4:_) = let
-- Local definition in `let`
Maybe pat5 = ...
in ...
第二个上下文:->
表达式中case
的左侧:
case expr of
Just pat -> 2*a
Nothing -> 42
第三个上下文:<-
中do
的左侧 - 符号或列表推导:
example1 = do
(pat1, pat2) <- ...
...
example2 = [f x y | (x, y) <- ...]
我可能会错过其他一些背景,但至少这些是主要的背景。
这里的另一个重要概念是数据构造函数:Haskell中的一个常量或运算符,它提供两个函数:
同样,数据构造函数的具体使用是否算作前者或后者,完全取决于它是否是左侧&#34;与#34;右侧&#34;使用它。
答案 2 :(得分:-1)
(以下内容并非严格正确;正如Shumush所指出的,模式匹配只能通过数据构造函数完成,而不仅仅是任何函数。下面提到的(:)
和Just
是实际的数据构造函数;各种逗号函数似乎并不存在,所以我实际上并不知道模式与元组的匹配是如何工作的。或许可以将其视为元组模式匹配的巧合类比。)
首先,使用map
的定义作为示例,考虑模式匹配如何应用于列表。
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x (map f xs)
在这里,您可以对列表进行模式匹配,因为(:)
是一个从元素和另一个列表生成列表的函数。也就是说,(x:xs)
可以匹配[1,2,3]
,将1绑定到x
,将[2,3]
绑定到xs
,因为(:) 1 [2, 3] = 1 : [2,3] = [1,2,3]
。
(,)
是一个产生元组的函数:
> :t (,)
(,) :: a -> b -> (a, b)
所以(,) 1 2 = (1, 2)
。因此,您可以使用与(,)
相同的方式与(:)
进行模式匹配:
(skinny, normal, fat) = (18.5, 25.0, 30.0)
(Prelude提供了(,,) :: a -> b -> c -> (a, b, c)
,(,,,)
的定义以及更多内容。)
将18.5绑定到skinny
,将25.0绑定到normal
,将30.0绑定到fat
,因为
(,) 18.5 25.0 30.0 = (18.5, 25.0, 30.0)
将模式匹配视为功能评估的对立面。您可以“拆分”一个值来获取用于生成该值的操作数,而不是将函数应用于值以生成新值。
模式匹配可以通过任何函数调用来完成,这就是为什么你可以对诸如Maybe
值之类的东西进行模式匹配
-- From the Functor instance of Maybe
fmap :: (a -> b) -> (Maybe a) -> (Maybe b)
fmap f Nothing = Nothing
fmap f (Just x) = f x
由于Just :: a -> Maybe a
是一个函数(特别是数据构造函数),因此您可以通过将Maybe
创建的Just
中包含的值绑定到x
来进行模式匹配。