2017-10-21 57 views
1

我尝试使用下面的代码打印在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 = "" 

第一个代码有什么问题?

+0

在'的printList(节点VN)','v'和'N'是参数,但在'x ==(Node vn)'中,它们是两个未定义的变量。 – ForceBru

+0

@ForceBru所以有办法区分哪个数据构造函数x正在使用? –

回答

4

通过使用相等性检查,您不会做模式匹配:有可能两个不同的模式被认为是相等的。

所以你可以做的是定义一个模式在你的函数的一个子句的头部。例如:

printList :: List -> String 
printList (Node v n) = show v ++ " " ++ printList n 
printList _ = show '_'

所以现在哈斯克尔会,因为如果它与Node v n模式匹配,和一个给定的List检查,如果这样解压元素和分配头v和尾部n

但是我们仍然可以改进代码。通常你最好不要使用通配符模式,而是使用所有可能的模式。因为如果你以后想改变的List定义,编译器可以给你,你忘了图案的警告:

printList :: List -> String 
printList (Node v n) = show v ++ " " ++ printList n 
printList Empty = show '_'

我们可以改善的另一件事是在show '_'使用"_"。由于show '_'会将内容加到中。例如:

printList :: List -> String 
printList (Node v n) = show v ++ " " ++ printList n 
printList Empty = "_"

最后,我们还可以使用 “缺点” 建设上有一个单列表附加:

printList :: List -> String 
printList (Node v n) = show v ++ ' ' : printList n 
printList Empty = "_"
+0

但我之前编写的一段代码有一个函数参数'x',与数据构造函数行'Meter'比较。代码如下:'数据MetricUnit = Meter |升| |千克 派生(Show,Eq)''returnMetricSymbol x | x ==米=“m” | x == Liter =“L” | x == Kilogram =“kg”' –

+1

@SafwanAhmad:这是因为(1)你添加了'derving Eq',并且(2)在这里你只检查是否相等,你不需要*解压缩构造函数,没有参数在你感兴趣的代码中。 –

+0

好吧,我的理解是,在guard语句中使用Data构造函数本质上是创建新变量,而如果我使用相同的Data构造函数作为函数参数,则它是模式匹配的。这意味着我的代码在上面的评论中是纯粹的机会,因为'Meter'正在创建一个新变量,与'x'进行比较,并且可以进行比较,因为我推导出了'Eq'。对? –