是否可以在Haskell中定义一个具有两种可能类型的输入参数的函数?

时间:2014-12-25 00:55:11

标签: haskell pattern-matching parametric-polymorphism

为了我自己的理解,我想在Haskell中定义一个带有两个参数的函数 - 无论是整数还是两个Chars。它对参数进行了一些微不足道的检查,如下:

foo 1 2 = 1
foo 2 1 = 0
foo 'a' 'b' = -1
foo _ _ = -10

我知道这不会编译,因为它不知道它的args是Num还是Char类型。但我无法使其论证具有多态性,例如:

foo :: a -> a -> Int

因为那时我们说它必须是身体中的Char(或Int)。

是否可以在Haskell中执行此操作?我想过可能会创建一个自定义类型?类似的东西:

data Bar = Int | Char
foo :: Bar -> Bar -> Int

但我不认为这也是有效的。总的来说,我很困惑Haskell中的函数是明确的ONE类型,还是类型类的多态,是否禁止在函数体中使用特定类型。

3 个答案:

答案 0 :(得分:5)

您可以使用Either数据类型存储两种不同的类型。这样的事情应该有效:

foo :: Either (Int, Int) (Char, Char) -> Int
foo (Right x) = 3
foo (Left y) = fst y

因此,对于Left数据构造函数,您将两个Int传递给它,对于它的Right构造函数,您将两个Char传递给它。另一种方法是定义您自己的代数数据类型,如下所示:

data MyIntChar = MyInt (Int, Int) | MyChar (Char, Char) deriving (Show)

如果观察,则可以看到上述类型与Either数据类型同构。

答案 1 :(得分:5)

我不确定我是否一定会建议使用类型类,但它们至少可以做到这样的事情。

class Foo a where
    foo :: a -> a -> Int

instance Foo Int where
    foo 1 2 = 1
    foo 2 1 = 0
    foo _ _ = -10

instance Foo Char where
    foo 'a' 'b' = -1
    foo _ _ = -10

答案 2 :(得分:3)

你可以做到

type Bar = Either Int Char

foo :: Bar -> Bar -> Int
foo (Left 1) (Left 2) = 1
foo (Right 'a') (Right 'b') = -1 
foo (Left 3) (Right 'q') = 42
foo _ _ = 10

之类的东西 - Either数据类型恰好用于将两种类型混合在一起。您可以滚动自己的类似类型,如

data Quux = AnInt Int | AChar Char | ThreeBools Bool Bool Bool

它被称为代数数据类型。

(我很难想到将特定字符和整数混合在一起有用的情况 - 主要是知道数据的位置和类型非常有用。)

也就是说,我经常编写代数数据类型,但我给它们提供了有意义的名称来代表实际的东西,而不是仅仅将随机的东西放在一起,因为我不喜欢具体。非常具体或完全一般是有用的。在它们之间有像Eq这样的类型类。您可以拥有一个类型为Eq a => a -> [a] -> Bool的函数,这意味着它对于已定义a -> [a] -> Bool的任何类型都具有类型==,我将其打开以供人们将其用于我从未想过的数据类型只要他们定义一个相等的函数。