元组字符串的模式匹配列表

时间:2017-01-16 21:29:17

标签: list haskell

所以我在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")]

你知道这里出了什么问题吗?

2 个答案:

答案 0 :(得分:6)

我不明白为什么你:

  1. 在模式匹配部分中使用emptybook,而不是[];
  2. 为什么在表达式的左侧和右侧重复(x:xs);
  3. 区分空书和非空书。
  4. 为什么它不起作用

    因为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定义为三个常规参数abemptyBook的函数。好吧,最后没有实际使用,但这没有区别 - 无论你传递什么参数,该子句都会成功。

第三个参数也阴影顶级定义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=(:).:(,)