案例或案例表达与模式匹配或可能吗?

时间:2019-03-29 11:00:20

标签: haskell

我正在独自学习haskell。并且正在努力使用基本列表和大小写实现自定义List数据类型。

所以数据结构与此类似

data List = List [String] | EmptyList deriving Show

现在,如果我要为基本用例进行大小写表达式,则必须进行两次匹配。一个简单的例子就是size函数

size :: List -> Int
size lst = case lst of
  (List []) -> 0
  EmptyList -> 0
  (List (x:xs)) -> 1 + size (List xs)

我是否可以通过某种方式合并列表为空的两个基本案例(List [])EmptyList来减少冗余?

size :: List -> Int
size lst = case lst of
  (List []) | EmptyList -> 0
  (List (x:xs)) -> 1 + size (List xs)

我试图在网上搜索所有内容,但是不幸的是,在一种情况下,无法找到匹配多个模式的具体内容。

2 个答案:

答案 0 :(得分:4)

首先,您应该首先考虑为什么要为ListEmptyList分别使用构造函数。无论如何,空列表显然已经是列表的一种特殊情况,因此这是一个笨拙的冗余。如果有的话,你应该做到

import Data.List.NonEmpty
data List' a = NEList (NonEmpty a) | EmptyList

适用于此特定示例的另一个选项是将空案例变成“全包模式”:

size :: List -> Int
size lst = case lst of
  (List (x:xs)) -> 1 + size (List xs)
  _ -> 0

顺便说一句,这里没有理由使用case,您也可以只编写两个函数子句:

size :: List -> Int
size (List (x:xs)) = 1 + size (List xs)
size _ = 0

无论如何-通常不建议这样做,因为如果将来扩展数据类型,那么包罗万象的子句很容易发现难以爬入的错误。

也可以,但更糟糕的样式是使用布尔值后卫匹配 –这可以轻松地在选项列表中使用查找,例如

size lst | lst`elem`[EmptyList, List []] = 0
size (List (x:xs)) = 1 + size (List xs)

如果可能,应避免进行平等检查;他们引入了Eq约束,这毫无必要,将要求 elements 是可比的。通常,相等性检查也比模式匹配在计算上更昂贵。

如果您无法更改数据结构本身,但是愿意想要使用它,就像List []EmptyList一样,这是另一种选择,那就是编写自定义模式同义词。这是Haskell的相对较新的功能; 假装的数据结构实际上与实际布局不同,例如List'

答案 1 :(得分:1)

在评论中,您说

  

没有此类函数[应该为EmptyListList []返回不同的结果]

因此,我建议在类型本身中合并这两个构造函数:

data List = List [String] deriving Show

现在,在使用EmptyList的函数中,您不再需要在List []List之间进行区分。

...事实上,我将走得更远,完全取消定义,只需在各处使用[String]即可。对此有一个例外:如果您需要为一个行为不同于[String]的现有实例的类定义一个实例。在这种特殊情况下,定义一种新类型是明智的;但出于通常的效率和语义原因,我将使用newtype而不是data