我想定义一个新的抽象数据类型,它是一般的Number或Division构造。我如何在Haskell中做到这一点?
我的第一个方法是:
data MyMath = MyNum Num
| Div MyMath MyMath
问题是编译器抱怨“Num”不是数据类型而是类型类。所以我的第二个想法是解决这个问题:
data MyMath = MyNum Int
| MyNum Float
| Div MyMath MyMath
但是这不会起作用,因为MyNum被使用了两次是不允许的,另外这种方法实际上不是多态的。那么这个问题的解决方案是什么?
EDIT2 :在(再次)阅读答案后,我尝试使用GADT数据构造函数。这是一些人为的示例代码:
5 data MyMathExpr a where
6 MyNumExpr :: Num a => a -> MyMathExpr a
7 MyAddExpr :: MyMathExpr b -> MyMathExpr c -> MyMathExpr (b, c)
8 deriving instance Show(MyMathExpr a)
9 deriving instance Eq(MyMathExpr a)
10
11 data MyMathVal a where
12 MyMathVal :: Num a => a -> MyMathVal a
13 deriving instance Show(MyMathVal a)
14 deriving instance Eq(MyMathVal a)
15
16 foo :: MyMathExpr a -> MyMathVal a
17 foo (MyNumExpr num) = MyMathVal num
18 foo (MyAddExpr num1 num2) = MyMathVal (l + r)
19 where (MyMathVal l) = foo num1
20 (MyMathVal r) = foo num2
但第18行出了点问题:
test.hs:18:40:
Couldn't match type `b' with `(b, c)'
`b' is a rigid type variable bound by
a pattern with constructor
MyAddExpr :: forall b c.
MyMathExpr b -> MyMathExpr c -> MyMathExpr (b, c),
in an equation for `foo'
at test.hs:18:6
In the first argument of `(+)', namely `l'
In the first argument of `MyMathVal', namely `(l + r)'
In the expression: MyMathVal (l + r)
“c”也是如此。我想这是一个愚蠢的错误,我只是看不到。你呢?
答案 0 :(得分:3)
这解决了您在代码中解决的问题,但没有涵盖布尔值。 如果你想在数据声明中使用类约束,你可以像使用任何其他函数一样:
data (Num a) => MyMath a = MyMath {x :: a}
答案 1 :(得分:3)
您可以使用存在量化:
> let data MyMath = forall n. Num n => MyNum n
> :t MyNum 3
MyNum 3 :: MyMath
> :t MyNum 3.5
MyNum 3.5 :: MyMath
答案 2 :(得分:1)
有很多方法可以做到这一点。一种方法是使用GADT:
{-# LANGUAGE GADTs #-}
data MyMath where
MyNum :: Num a => a -> MyMath
MyBool :: Bool -> MyMath
GADT的另一种方式:
{-# LANGUAGE GADTs #-}
data MyMath a where
MyNum :: Num a => a -> MyMath a
MyBool :: Num a => Bool -> MyMath a
答案 3 :(得分:0)
正如已经提到的,你的尝试不涉及任何布尔,但我会改为你的问题文本。
您不必创建此类型,请在Prelude中查看Either。因此,您所需要的是Either a Bool
,您希望a
成为Num
的实例。如果您想要实际执行此操作,请准备好以下编辑。
修改:如果您不想使用Either
,则可以执行data MyMath a = MyNum a | MyBool Bool
。现在,如果您愿意,可以强制a
成为Num
的实例,但您可能需要先考虑this SO question和this answer to it。实际上没有必要为数据类型强制实例;只是为使用它的函数做到这一点。