所以我在Haskell中丢失了String元组。 我宣布了一种类型:
type Book = [(String, String)]
然后我宣布了一本空书:
emptyBook :: Book
emptyBook = []
现在我想创建一个将元素插入到书中的函数。我的解决方案:
insert :: String -> String -> Book -> Book
insert a b emptyBook = (a,b) : []
insert a b (x : xs)= (a, b) : (x:xs)
但是功能插入不起作用。编译器加载模块但提供警告'模式匹配是多余的'。
执行插入"a" "1" [("b","2")]
会[("a","1")]
而不是[("a","1"),("b","2")]
你知道这里出了什么问题吗?
答案 0 :(得分:6)
我不明白为什么你:
emptybook
,而不是[]
; (x:xs)
; 因为Haskell像许多其他语言一样使用变量作用域,而Haskell在函数中看到emptybook
作为变量。它没有看到(至少不存在)emptybook
是某个定义的函数。所以可以写:
insert a b c = (a,b) : []
(作为函数定义中的第二行)。现在既然你定义了一个变量c
并且没有对它施加任何约束(守卫,模式......),那么匹配所有内容:所以也是一本非空书。因此Haskell将始终占据第一线。事实上,编译器已经警告过你了。它说:
haskell.hs:9:1: Warning:
Pattern match(es) are overlapped
In an equation for ‘insert’: insert a b (x : xs) = ...
这意味着函数定义的最后一行与前一行重叠。在那种情况下,你可能做错了。
您可以简单地使用:
insert :: String -> String -> book -> book
insert a b xs = (a,b) : xs
甚至更短:
insert :: String -> String -> book -> book
insert a b = (:) (a,b)
此外,类型通常用大写字母表示,因此您最好使用Book
代替book
。
答案 1 :(得分:4)
条款
insert a b emptyBook = (a,b) : []
将insert
定义为三个常规参数a
,b
和emptyBook
的函数。好吧,最后没有实际使用,但这没有区别 - 无论你传递什么参数,该子句都会成功。
第三个参数也阴影顶级定义emptyBook
- 基本上这使得它在函数范围内,emptyBook
现在是你通过的任何书在,不管它是否为空。
如果你告诉它提供慷慨的警告,GHC实际上可以发出警告,强调你的代码存在这个真正的问题:
sagemuej@sagemuej-X302LA:~$ runhaskell -Wall /tmp/wtmpf-file2776.hs
/tmp/wtmpf-file2776.hs:7:12: Warning:
This binding for ‘emptyBook’ shadows the existing binding
defined at /tmp/wtmpf-file2776.hs:4:1
/tmp/wtmpf-file2776.hs:7:12: Warning:
Defined but not used: ‘emptyBook’
如果您希望emptyBook
成为应匹配的常量,则必须明确指出这不是新绑定的参数变量。有两种选择:
( 不 推荐)使用等式比较代替模式匹配
insert a b book
| book==emptyBook = (a,b) : []
insert a b (x : xs) = (a, b) : (x:xs)
我们通常避免在Haskell中进行相等比较 - 它比模式匹配更不通用,效率更低,更容易出错。
(非常不 推荐)使用C预处理器宏(模板Haskell也可以工作)实际在该模式中插入[]
匹配。你不能拥有一个名为[]
的变量,所以这会做正确的事情:
{-# LANGUAGE CPP #-}
#define emptyBook []
insert :: String -> String -> Book -> Book
insert a b emptyBook = (a,b) : []
insert a b (x : xs) = (a, b) : (x:xs)
这些宏定义与Haskell不能很好地协同工作 - 他们完全忘记了语言范围,无法导出等等。
(不非常 推荐)使用模式同义词。这些本质上是现代的Haskell本地方式,用CPP宏实现我在上面做的行为:
{-# LANGUAGE PatternSynonyms #-}
pattern EmptyBook :: Book
pattern EmptyBook = []
insert :: String -> String -> Book -> Book
insert a b emptyBook = (a,b) : []
insert a b (x : xs) = (a, b) : (x:xs)
那么,将作为推荐的解决方案?好吧,正如Willem Van Onsem所说,你根本不需要那个条款 - 它已经是第二个条款的特例!
insert :: String -> String -> Book -> Book
insert a b (x : xs) = (a, b) : (x:xs)
...与
相同insert a b (x : xs) = (a, b) : x : xs
或
insert a b xxs = (a, b) : xxs
或
insert a b = ((a, b) :)
或
import Data.Function.Pointless
insert=(:).:(,)