我是新手Haskell,我正在阅读" 了解你一个Haskell",并在页面中宣布了一个函数
tell :: (Show a) => [a] -> String
tell [] = "The list is empty"
tell (x:[]) = "The list has one element: " ++ show x
tell (x:y:[]) = "The list has two elements: " ++ show x ++ " and " ++ show y
tell (x:y:_) = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y
Run Code Online (Sandbox Code Playgroud)
哪个工作正常.这本书说
这个函数是安全的,因为它处理空列表,单例列表,包含两个元素的列表和包含两个以上元素的列表.注意,(x:[])和(x:y:[])可以重写为[x]和[x,y](因为它的合成糖,我们不需要括号).我们不能用方括号重写(x:y:_),因为它匹配任何长度为2或更长的列表.
我尝试通过将最后一行改为来做到这一点
-- same as before
tell [x:y:_] = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y
Run Code Online (Sandbox Code Playgroud)
和哈斯克尔提出了一个非常丑陋的信息
Could not deduce (a ~ [a0])
from the context (Show a)
bound by the type signature for tell :: Show a => [a] -> String
at C:\Documents and Settings\Razor\Desktop\Other\baby.hs:(24,1)-(27,9
5)
`a' is a rigid type variable bound by
the type signature for tell :: Show a => [a] -> String
at C:\Documents and Settings\Razor\Desktop\Other\baby.hs:24:1
In the pattern: x : y : _
In the pattern: [x : y : _]
In an equation for `tell':
tell [x : y : _]
= "This list is long. The first two elements are: "
++ show x ++ " and " ++ show y
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释什么是错的吗?而作为每本书,我可以写(x:[])为[x](我做到了,只是可以肯定的),但我为什么不能写tell (x:y:_)的tell [x:y:_].而且我知道书给出了描述,但我真的无法理解这是什么问题?任何人都能用清楚的语言解释它吗?
[x:y:_]
Run Code Online (Sandbox Code Playgroud)
是一个模式,它匹配一个只有一个元素的列表,这是一个至少包含两个元素的列表.
模式可以嵌套,因此您可以使用例如foo (Just (x:xs)) = ...匹配Maybe [a]包装非空列表的值.嵌套模式可能需要括在括号中,但它们并不总是如此.在上面,我们可以使用括号(和空格)来强调模式的解释方式:
tell [ (x:y:_) ] = "This list ..." ...
Run Code Online (Sandbox Code Playgroud)
我们有顶级模式[ element ],element它本身就是x:y:_匹配具有至少两个元素的列表的模式.总而言之,模式匹配单元素列表,其元素是长度至少为2的列表.
因此,当您使用该模式时
tell [x:y:_] = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y
Run Code Online (Sandbox Code Playgroud)
编译器推断tell出列表列表作为参数,
tell :: (Show [b]) => [[b]] -> String
Run Code Online (Sandbox Code Playgroud)
但是你的签名
tell :: (Show a) => [a] -> String
Run Code Online (Sandbox Code Playgroud)
承诺tell适用于任何可用show元素列表,而不仅仅是列表列表.
推断类型和指定类型之间的不匹配是编译器抱怨的内容
Could not deduce (a ~ [a0])
Run Code Online (Sandbox Code Playgroud)
(GHC选择命名类型变量a0,我选择b,这无关紧要).
符号[x]分别为 [x,y,z]是语法糖,列表的元素用逗号分隔,并且在逗号之间可以出现任意模式(例如,当[x,y,z]在模式上下文中使用时,表达式上下文中的表达式)x:y:_,但每个模式对应于单个元素的清单.这样的模式[x,y,z,w]只匹配具有与子模式一样多的元素的列表(并且每个元素必须与相应的子模式匹配).
另外,我不明白的是,为什么它允许
(x:[])和(x:y:[])被rewriten为[x]和[x,y]?
这就是语法糖.通常,模式是
'a',"example"(这是语法糖的一种特殊情况,实际上), 3.4(这也是一种特殊的情况下,使用一个相等的比较==不同于通常的图案),_它匹配任何东西并且不绑定任何东西,name匹配任何内容并将相应的参数绑定到name,或True,Just x(被施加的构造的参数本身的模式,所以-见上文- Just (x:xs)也是可能的)(还有as-patterns list@(hd : tl)和lazy pattern ~pattern.)
列表构造函数是[](空列表)和(:)(通常说"cons",它构造一个元素的列表(它成为构造列表的头部)和另一个列表(它成为尾部),类型是(:) :: a -> [a] -> [a]),所以列表的构造函数模式
[] 对于空列表,和x:xs对于非空列表,将传递列表的头部绑定到名称x,将尾部绑定到名称xs.你可以嵌套(:)模式,例如
x : (y : (z : ws))
Run Code Online (Sandbox Code Playgroud)
并且,由于权限的相关性(:),您可以省略嵌套模式中的括号
x : y : z : ws
Run Code Online (Sandbox Code Playgroud)
对于列表,有一类进一步的模式,方括号之间的逗号分隔元素列表,
[x1, x2]
[x1, x2, x3, x4]
Run Code Online (Sandbox Code Playgroud)
依此类推,匹配列表与括号之间写的元素数量完全相同.这些被认为比相应的构造函数应用程序更容易
x1 : x2 : []
x1 : x2 : x3 : x4 : []
Run Code Online (Sandbox Code Playgroud)
两种形式的模式都是等价的(因此[x:y:_]也可以写成
(x:y:_) : []
Run Code Online (Sandbox Code Playgroud)
如果有人想).
我知道
x:[]是捷径[x],但其他人呢?
反过来说,[x]是糖x : [],并且[x,y]是语法糖x : (y : []).以同样的方式,
[x:y:_]
Run Code Online (Sandbox Code Playgroud)
是语法糖
(x : (y : _)) : []
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
180 次 |
| 最近记录: |