Haskell 使用保护的函数中存在变量不在范围内错误

Haskell 使用保护的函数中存在变量不在范围内错误,haskell,Haskell,我正在尝试使用以下代码在Haskell中打印链接列表: data List = Node {value:: Double, next:: List} | Empty printList :: List -> String printList x | x == (Node v n) = show v ++ " " ++ printList n | otherwise = show '_' 以及获取编译错误: :load scratch.hs

我正在尝试使用以下代码在Haskell中打印链接列表:

data List = Node {value:: Double, next:: List}
          |   Empty

printList :: List -> String
printList x | x == (Node v n) = show v ++ " " ++ printList n
            | otherwise = show '_'
以及获取编译错误:

:load scratch.hs
[1 of 1] Compiling Main             ( scratch.hs, interpreted )

scratch.hs:5:26: error: Variable not in scope: v :: Double

scratch.hs:5:28: error: Variable not in scope: n :: List

scratch.hs:5:38: error: Variable not in scope: v

scratch.hs:5:53: error: Variable not in scope: n :: List
Failed, modules loaded: none.
而我可以在没有防护装置的情况下使用模式匹配来实现同样的功能

printList (Node v n) = show v ++ " " ++ printList n
printList Empty = ""
第一个代码有什么问题?

您没有使用相等检查进行模式匹配:可能两个不同的模式被视为相等

因此,您可以在函数的某个子句的头部定义一个模式。例如:

printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList _ = show '_'
printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList Empty = "_"
我们可以改进的另一件事是使用
而不是
show'
。因为
show'.
会在内容中添加引号。例如:

printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList _ = show '_'
printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList Empty = "_"
printList::List->String
打印列表(节点v n)=显示v++++++++
printList Empty=“\u1”
最后,我们还可以使用一个“cons”结构来附加一个单例列表:

printList :: List -> String
printList (Node v n) = show v ++ ' ' : printList n
printList Empty = "_"
printList::List->String
打印列表(节点v n)=显示v++'':打印列表n
printList Empty=“\u”
您不使用相等检查进行模式匹配:可能两个不同的模式被视为相等

因此,您可以在函数的某个子句的头部定义一个模式。例如:

printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList _ = show '_'
printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList Empty = "_"
我们可以改进的另一件事是使用
而不是
show'
。因为
show'.
会在内容中添加引号。例如:

printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList _ = show '_'
printList :: List -> String
printList (Node v n) = show v ++ " " ++ printList n
printList Empty = "_"
printList::List->String
打印列表(节点v n)=显示v++++++++
printList Empty=“\u1”
最后,我们还可以使用一个“cons”结构来附加一个单例列表:

printList :: List -> String
printList (Node v n) = show v ++ ' ' : printList n
printList Empty = "_"
printList::List->String
打印列表(节点v n)=显示v++'':打印列表n

printlistempty=“”
printList(Node v n)
中,
v
n
是参数,但在
x==(Node v n)
中,它们是两个未定义的变量。@ForceBru那么有没有办法区分x使用的数据构造函数?在
printList(Node v n)
中,
v
n
是参数,但是在
x==(Node v n)
中,它们是两个未定义的变量。@ForceBru那么有没有办法区分x使用的是哪个数据构造函数呢?但是我之前写的一段代码有一个函数参数
x
与数据构造函数行
Meter
进行比较。代码如下:
data MetricUnit=Meter | L | kg推导(Show,Eq)
returnMetricSymbol x | x==Meter=“m”| x==L=“L”| x==kg=“kg”@SafwanAhmad:这是因为(1)您添加了
derving Eq
,并且(2)这里您只检查等式,不需要解包构造函数,代码中没有您感兴趣的参数。所以我的理解是,在guard语句中使用数据构造函数实际上是在创建新变量,而如果使用相同的数据构造函数作为函数参数,则它是模式匹配的。这意味着我在上面评论中的代码完全是偶然工作的,因为
Meter
正在创建一个新变量,该变量将与
x
进行比较,并且比较是可能的,因为我已导出
Eq
。对吧?或多或少。通过
导出Eq
,您已经隐式定义了一个函数
(==)::MetricUnit->MetricUnit->Bool
。但是对于Haskell来说,
=
只是另一个函数。因此,对于Haskell来说,
x==Meter
并不比
otherFunction x Meter
更特殊。它只是计算这个值,然后返回
True
。但是我前面编写的一段代码有一个函数参数
x
,与数据构造函数line
Meter
进行比较。代码如下:
data MetricUnit=Meter | L | kg推导(Show,Eq)
returnMetricSymbol x | x==Meter=“m”| x==L=“L”| x==kg=“kg”@SafwanAhmad:这是因为(1)您添加了
derving Eq
,并且(2)这里您只检查等式,不需要解包构造函数,代码中没有您感兴趣的参数。所以我的理解是,在guard语句中使用数据构造函数实际上是在创建新变量,而如果使用相同的数据构造函数作为函数参数,则它是模式匹配的。这意味着我在上面评论中的代码完全是偶然工作的,因为
Meter
正在创建一个新变量,该变量将与
x
进行比较,并且比较是可能的,因为我已导出
Eq
。对吧?或多或少。通过
导出Eq
,您已经隐式定义了一个函数
(==)::MetricUnit->MetricUnit->Bool
。但是对于Haskell来说,
=
只是另一个函数。因此,对于Haskell来说,
x==Meter
并不比
otherFunction x Meter
更特殊。它只是计算这个值,然后返回
True