Haskell模式匹配类型

16
有没有在Haskell中实现类似这样的功能的方法?
data Fruits = Apple Int | Orange Int deriving (Eq, Show)

basket = [Apple 2, Orange 4]

from_basket t (x:basket) =
    case x of
        (t i) -> i
        _ -> from_basket t basket

现在我想从水果列表(篮子)中获取“苹果”。
from_basket Apple basket

没有明确的模式匹配

case x of
    Apple i -> ...
    Orange i -> ...
    _ ->

似乎是 https://dev59.com/C1LTa4cB1Zd3GeqPXyqi 的几乎完全重复。 - Carl
2
@Carl:我认为这并不是“几乎完全相同”。在另一个问题中,OP想要检查一个变量是否属于某种类型(这在编译时决定)。而在这里,问题是常量类型的哪个构造函数被调用了(这在运行时决定)。 - musiKk
3个回答

16

一种方法是定义你自己的帮助函数 isApple,然后进行过滤:

isApple (Apple _) = True
isApple _         = False

getApples = filter isApple

模式匹配是您首选的工具,我不知道您是否可以进一步简化此过程。但除了一些糟糕的Template Haskell外,我没有看到其他方法。


这将返回[Fruits],而不是Int - user395760
@delnan: 所以你可以把它链起来得到Int: head . map (\Apple i -> i) . filter isApple - rampion
这在这种情况下似乎比“Maybe”方法稍微更清晰,并且如果没有苹果,则可以访问篮子中的所有苹果或[],这也可能很有用。 - Owen S.

12

其他答案已经解释了为什么原来的方法行不通,但是就替代方案而言,希望像那样做往往意味着你的数据类型应该更像这样:

data FruitName = Apple | Orange deriving (Eq, Show)
data Fruits = Fruits FruitName Int deriving (Eq, Show)

...在这种情况下,所需的函数变得微不足道。


9
你能为那些无法看到这个例子的琐碎之处而详细解释一下吗? - unode

5
您可以通过定义选择器函数来实现类似的功能。
getApple :: Fruits -> Maybe Int
getApple (Apple x) = Just x
getApple _ = Nothing

getOrange :: Fruits -> Maybe Int
getOrange (Orange x) = Just x
getOrange _ = Nothing

fromBasket selector [] = Nothing
fromBasket selector (x:basket) =
    case selector x of
        Just x -> Just x
        Nothing -> fromBasket selector basket

现在您可以做到:
> fromBasket getApple basket
Just 2

> fromBasket getOrange basket
Just 4 

假定您的构造函数都接受类似的参数。如果所需的水果类型不在篮子里,则返回“nothing”。

1
你已经在使用 Maybe 了 - 为什么不把 fromBasket :: [Fruits] -> Maybe Fruits 也改一下,避免使用 "邪恶" 的 error 呢?比如说 fromBasket selector [] = Nothing (我认为这个要放在最前面)。 - user395760
是的,在这里有道理。我已经更新了代码。空列表情况不必放在第一位,因为(:)构造函数与[]不匹配,但将空列表情况放在第一位被认为更符合惯用法。谢谢 :) - hammar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接