gpt4 book ai didi

haskell - 这个非常基本的函数声明有什么问题?

转载 作者:行者123 更新时间:2023-12-02 21:32:43 25 4
gpt4 key购买 nike

我是 Haskell 的新手,我正在阅读 Learn you a 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

哪个工作正常。书上说

This function is safe because it takes care of the empty list, a singleton list, a list with two elements and a list with more than two elements. Note that (x:[]) and (x:y:[]) could be rewriten as [x] and [x,y] (because its syntatic sugar, we don't need the parentheses). We can't rewrite (x:y:_) with square brackets because it matches any list of length 2 or more.



我试图通过将最后一行更改为
-- same as before
tell [x:y:_] = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y

Haskell 提出了一个非常丑陋的信息
    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.

任何人都可以解释什么是错的?根据书,我可以写 (x:[])[x] (我确实这样做了),但是为什么我不能写 tell (x:y:_)tell [x:y:_] .我知道书给出了描述,但我真的不明白有什么问题?谁能用清晰的语言解释一下?

最佳答案

[x:y:_]

是一种模式,它匹配一个只有一个元素的列表,它是一个至少有两个元素的列表。

模式可以嵌套,例如可以使用 foo (Just (x:xs)) = ...匹配 Maybe [a]包装非空列表的值。嵌套模式可能需要用括号括起来,但并不总是如此。在上面,我们可以使用括号(和空格)来强调模式的解释方式:
tell [ (x:y:_) ] = "This list ..." ...

我们有顶级模式 [ element ] , 和 element本身就是模式 x:y:_匹配包含至少两个元素的列表。总之,该模式匹配单元素列表,其元素是长度至少为 2 的列表。

因此,当您在
tell [x:y:_] = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y

编译器推断 tell将列表列表作为参数,
tell :: (Show [b]) => [[b]] -> String

但是你的签名
tell :: (Show a) => [a] -> String

promise tell适用于 show 的任何列表有能力的元素,不仅有列表的列表。

推断类型与指定类型之间的不匹配是编译器在
    Could not deduce (a ~ [a0])

(GHC 选择命名类型变量 a0 ,我选择了 b ,没关系)。

符号 [x]分别 [x,y,z]是语法糖,列表的元素用逗号分隔,逗号之间可以出现任意模式(当 [x,y,z]用于模式上下文时,表达式在表达式上下文中),例如 x:y:_ ,但每个模式对应于列表的单个元素。这样的格局 [x,y,z,w]仅匹配具有与子模式一样多的元素的列表(并且每个元素必须匹配相应的子模式)。

Also, what I don't get is, why does it allows (x:[]) and (x:y:[]) to be rewriten as [x] and [x,y]?



这就是语法糖。一般来说,一个模式是
  • 文字,'a' , "example" (实际上这是语法糖的一个特例),3.4 (这也是一种特殊情况,它使用相等比较 == 与通常的模式不同),
  • 通配符,_ ,它匹配任何东西并且不绑定(bind)任何东西,
  • 标识符,name ,它匹配任何东西并将相应的参数绑定(bind)到 name , 或
  • 一个完全应用的值构造函数,True , Just x (应用构造函数的参数本身就是模式,所以 - 见上文 - Just (x:xs) 也是可能的)

  • (还有 as-patterns list@(hd : tl) 和惰性模式 ~pattern 。)

    列表构造函数是 [] (空列表)和 (:) (通常说“缺点”,它从一个元素(成为构造列表的头部)和另一个列表(成为尾部)构造一个列表,类型是 (:) :: a -> [a] -> [a] ),所以列表的构造函数模式是
  • []对于空列表,
  • x:xs对于非空列表,将传递列表的头部绑定(bind)到名称 x和名字的结尾xs .

  • 可以嵌套 (:)模式,例如
    x : (y : (z : ws))

    并且,由于 (:) 的右结合性, 你可以省略嵌套模式中的括号
    x : y : z : ws

    对于列表,还有一类进一步的模式,方括号之间的逗号分隔元素列表,
    [x1, x2]
    [x1, x2, x3, x4]

    依此类推,它们匹配列表中的元素与括号之间的元素数量完全相同。这些在视觉上被认为比相应的构造函数应用程序更容易
    x1 : x2 : []
    x1 : x2 : x3 : x4 : []

    两种形式的模式是等价的(因此 [x:y:_] 也可以写成
    (x:y:_) : []

    如果有人愿意)。

    I know x:[] is shortcut for [x], but what about other one?



    反过来, [x]x : [] 的糖, 和 [x,y]x : (y : []) 的语法糖.同样的方式,
    [x:y:_]

    是语法糖
    (x : (y : _)) : []

    关于haskell - 这个非常基本的函数声明有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16692694/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com