函数来处理多个现有独立的数据定义

函数来处理多个现有独立的数据定义

问题描述:

我有多个数据定义,作为一个简单的例子:函数来处理多个现有独立的数据定义

data Fruit = Apple String Bool 
      | Cherry String String 
      | Grape String 

data Vegetable = Carrot String 
       | Onion Bool String 
       | Tomato String String 

现在我想有应进行两种类型的函数,我想是这样的:

f :: a -> String 
f (Carrot s) = s 
f (Apple s b) = s 
f (Onion b s) = s 
... 

但是这不起作用,因为预期类型a不能与例如类型Carrot匹配。我想知道如何在模式匹配或其他技术的帮助下定义一个可以处理多个现有独立数据定义的函数。

+2

您可以定义一个'˚F::无论是果蔬 - > String',也可以定义一个类型类(和定义两个'f's)。 –

+0

@WillemVanOnsem谢谢你的提示。我是对的,'只有'只有两种类型? –

+2

没有一种类型,即“任何水果蔬菜”类型。所以你写'f(Left(Apple s b))= ...','f(Right(Carrot c))= ...'。 –

做你正在尝试做的方法是与同时涉及食品新的数据类型,所以,让我们把它叫做食物,这将是:

data Food = Veg Vegetable | Fr Fruit deriving Show 

data Fruit = Apple String Bool 
      | Cherry String String 
      | Grape String deriving Show 

data Vegetable = Carrot String 
       | Onion Bool String 
       | Tomato String String deriving Show 


f :: Food -> String 
f (Veg v) = fVeg v 
f (Fr f) = fFruit f 

fVeg (Carrot s) = s 
fVeg (Onion b s) = s 
fVeg (Tomato s1 s2) = s1 ++ s2 

fFruit (Apple s b) = s 
... 
... 

    f $ Veg $ Onion True "friend" 
=> "friend" 
+0

非常感谢。非常干净的解决方案,无需更改现有类 –

+0

@ClaudioP没问题!我一直很喜欢帮助,我希望你接受两个答案中的一个:) –

有两个选项。一个是Damian Lattenero说的,另一个选择是使用typeclasses。

class Food a where 
    f :: a -> String 

instance Food Fruit where 
    f (Apple ...) = ... 
    f (Cherry ...) = ... 
    f ... 

instance Food Vegetable where 
    f (Carrot ...) = ... 
    f (Onion ...) = ... 
    f (Tomato ...) = ... 

问题是你不能有,例如,食物的列表,因为水果和蔬菜是不同的类型。但是你可以在没有问题的情况下使用f。

编辑:

另一种选择,存在量化,以在列表中有两种类型,但是只将f应用到数据(也使用上面的代码):

{-# LANGUAGE ExistentialQuantification #-} 

data F = forall a. (Food a) => F a 

instance Food F where 
    f (F x) = f x 

xs :: [F] 
xs = [F (Apple ...), F (Carrot ..), F (Tomato ...)] 

的一个例子,函数使用F:

mapF :: [F] -> [String] 
mapF xs = map f xs 
+2

请注意,typeclasses + existstentials通常会导致[已知的反模式](https://lukepalmer.wordpress.com/2010/01/24/haskell -antipattern-存在-类型类/) – chi