简体   繁体   English

在Haskell的模式匹配中是否特别处理了“List”?

[英]Is “List” specially handled in Haskell's pattern matching?

I am a newbie in Haskell and hope this question is not silly. 我是Haskell的新手,希望这个问题不傻。

I have seen so much example that when I am having a list, I am able to match and bind "composition element" of the list to individual variable: 我已经看到了很多例子,当我有一个列表时,我能够匹配并将列表的“组合元素”绑定到单个变量:

listSizeDesc :: [a] -> String
listSizeDesc [] = "Emtpy"
listSizeDesc (x:xs) = "Something inside"

However, I tried to do something like: 但是,我尝试做类似的事情:

foo :: Int -> String
foo 0 = "Zero"
foo (n - 1) = "next number is " ++ show n

It doesn't work. 它不起作用。

It seems to me that both (n-1) and (x:xs) describe how the argument is "created" and bind the "component" to an argument. 在我看来,(n-1)和(x:xs)都描述了如何“创建”参数并将“组件”绑定到参数。 Is the way List matched specially designed for ease of recursion? List的匹配方式是为了便于递归而专门设计的吗? Coz it seems to me this matching / argument-binding logic doesn't apply to other functions except (:). 因为在我看来,这个匹配/参数绑定逻辑不适用于除(:)之外的其他函数。

The problem you're encountering is that pattern matching only works with data constructors. 您遇到的问题是模式匹配仅适用于数据构造函数。 A data constructor is in essence very simple; 数据构造函数本质上非常简单; it just takes data values and groups them together in some sort of structure. 它只需要采用数据值并将它们组合在一起。 For example, data Foo = Bar ab simply takes two pieces of data and groups them together under the Foo label. 例如, data Foo = Bar ab只需要两个数据并在Foo标签下将它们组合在一起。 The (:) function you use in your first example is more than just a function; 您在第一个示例中使用的(:)函数不仅仅是一个函数; it's a data constructor. 它是一个数据构造函数。 It constructs a new list by adding the left argument to the right argument. 它通过向左参数添加左参数来构造新列表。

Now, pattern matching is merely doing the opposite of this process. 现在,模式匹配仅仅与此过程相反。 It deconstructs a datatype. 它解构了一种数据类型。 When you write (x:xs) in your pattern, you're extracting the two pieces of data that the constructor originally stitched together. 当您在模式中编写(x:xs)时,您将提取构造函数最初拼接在一起的两个数据。 So all pattern matching does is extract the data that a constructor previously stitched together. 因此,所有模式匹配都会提取构造函数先前拼接在一起的数据。

There is one exception: n+k patterns. 有一个例外:n + k模式。 In Haskell98, you were allowed to use patterns of the form (n+k). 在Haskell98中,您被允许使用形式(n + k)的模式。 This was sort of an arbitrary exception and it was recently removed. 这是一种任意的例外,它最近被删除了。 If you'd like, you can still use it if you include the NPlusKPatterns language pragma. 如果您愿意,如果包含NPlusKPatterns语言编译指示,仍可以使用它。

The list type is "Sum type" with a constructor, something like: 列表类型是带有构造函数的“Sum type”,类似于:

data List a =
     cons a (List a)
   | nil

You first example is a pattern match on a datatype (with syntactic sugar for : ). 你第一个例子是在数据类型的模式匹配(与语法糖: )。

Your second example is a pattern match on integers, which are not a datatypye definition. 第二个示例是整数上的模式匹配,它不是数据类型定义。 On integer, there is no pattern using your syntax. 在整数上,没有使用语法的模式。 You may write your example with: 你可以写下你的例子:

foo :: Int -> String
foo 0 = "Zero"
foo n = "next number is " ++ show (n+1)

On a side note if you encode integers with datatypes like: 如果您使用以下数据类型对整数进行编码,请注意:

data Nat = Zero | Succ Nat deriving (Show)

Then you can use your pattern match as you wanted initially. 然后,您可以根据需要使用模式匹配。

foo :: Nat -> String
foo Zero = "Zero"
foo n@Succ(p) = "next number is " ++ show(n)

Here the pattern Succ(p) plays the role of n-1 . 这里的模式Succ(p)n-1的作用。

There are already some great answers, so I won't bother with the main question. 已经有了一些很好的答案,所以我不会理会主要问题。 This is not the best use of it, but what you were trying to do can sort of be accomplished with view patterns . 不是最佳用途,但您尝试做的事情可以通过视图模式完成。

{-# LANGUAGE ViewPatterns #-}

foo :: Int -> String
foo 0 = "Zero"
foo (pred -> n) = "Next number is " ++ show n

Just to put it as simply as possible: 只是为了尽可能简单地说:
A list literally is a series of concatenations. 字面上的列表一系列连接。 A number could be equivalent to the result of an arithmetic operation. 数字可以等于算术运算的结果。 The difference is that the result of a : b is simply a : b . 区别在于a : b的结果只是a : b


In more detail: 更详细:

Lists and (:) aren't a special case at all. 列表和(:)根本不是特例。 Let's make our own: 让我们自己做:

data List2 a = End               -- equivalent of "[]"
             | Cat a (List2 a)   -- non-infix ":"
  deriving (Show)

So [1, 2, 3] , which == (1 : (2 : (3 : []))) , would be written as: 所以[1, 2, 3] ,= = (1 : (2 : (3 : []))) ,写成:

a = Cat 1 (Cat 2 (Cat 3 End))

Just like pattern-matching (x:xs) , we can pattern-match List2: 就像模式匹配(x:xs) ,我们可以模式匹配List2:

newTail End = End
newTail (Cat _ x) = x

Test it: 测试一下:

*Main> tail [1,2,3]
[2,3]
*Main> newTail a
Cat 2 (Cat 3 End)
moo :: Int -> String
moo 0 = "Zero"
moo n = "next number is " ++ show (n + 1)

n - 1 is an ordinary function application, not a pattern. n - 1是普通的函数应用程序,而不是模式。 An exception used to be made for + and this might be the model you are going by. 以前是一个例外+ ,这可能是你要去的模型。 You can write something like 你可以写类似的东西

goo :: Int -> String
goo 0 = "Zero"
goo (n+1)  = "previous number is " ++ show n

in hugs ; hugs ; you still can do this with the ghc , if you include the pragma 如果你包括pragma,你仍然可以用ghc做到这一点

{-#LANGUAGE NPlusKPatterns#-}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM