3

就我自己的理解而言,我想在 Haskell 中定义一个函数,它接受两个参数——要么都是整数,要么都是字符。它对参数进行了一些琐碎的检查,如下所示:

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 类型或多态到类型类之间存在中间立场,禁止在函数体中使用特定类型。

4

3 回答 3

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
于 2014-12-25T01:59:43.020 回答
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数据类型同构。

于 2014-12-25T01:21:50.600 回答
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已定义的任何类型的类型==,并且我将它留给人们使用它来处理我从未想过的数据类型,只要他们定义了一个相等函数。

于 2014-12-25T01:27:15.343 回答