Class 如何定义抽象数据类型,如;数据MyMath=MyNum";?

Class 如何定义抽象数据类型,如;数据MyMath=MyNum";?,class,haskell,types,abstract-data-type,Class,Haskell,Types,Abstract Data Type,我想定义一个新的抽象数据类型,它可以是一个普通数,也可以是一个除法构造。在哈斯克尔我该怎么做 我的第一个方法是: data MyMath = MyNum Num | Div MyMath MyMath 问题是编译器抱怨“Num”不是数据类型,而是类型类。所以我的第二个想法是解决这样的问题: data MyMath = MyNum Int | MyNum Float | Div MyMath MyMath 但这也不起作用,

我想定义一个新的抽象数据类型,它可以是一个普通数,也可以是一个除法构造。在哈斯克尔我该怎么做

我的第一个方法是:

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”也是如此。我想这是一个愚蠢的错误,我只是不明白。是吗?

如前所述,你的尝试不涉及任何布尔人,但我将用你问题的文本代替

你不必发明这种类型,请在前奏曲中查看。因此,您要查找的是
或Bool
,您希望
a
成为
Num
的实例。如果要实际执行此操作,请准备好下面的编辑


编辑:如果您不想使用
,可以执行
数据MyMath a=MyNum a | MyBool Bool
。现在,您可以强制执行<代码> < <代码>,它是<代码> Num < /代码>的实例,如果您愿意,但您可能需要考虑并首先考虑。实际上不需要为数据类型强制执行实例;只需对使用intsead的函数执行此操作。

这解决了代码中要解决的问题,但不包括布尔值。 如果要在数据声明中使用类约束,请使用与任何其他函数相同的方法:


data(Num a)=>MyMath a=MyMath{x::a}

您可以使用存在量化:

> let data MyMath = forall n. Num n => MyNum n
> :t MyNum 3
MyNum 3 :: MyMath
> :t MyNum 3.5
MyNum 3.5 :: MyMath

有很多方法可以做到这一点。一种方法是使用GADT:

{-# LANGUAGE GADTs #-}

data MyMath where
    MyNum :: Num a => a -> MyMath
    MyBool :: Bool -> MyMath
{-# LANGUAGE GADTs #-}

data MyMath a where
    MyNum :: Num a => a -> MyMath a
    MyBool :: Num a => Bool -> MyMath a
GADT的另一种方式:

{-# LANGUAGE GADTs #-}

data MyMath where
    MyNum :: Num a => a -> MyMath
    MyBool :: Bool -> MyMath
{-# LANGUAGE GADTs #-}

data MyMath a where
    MyNum :: Num a => a -> MyMath a
    MyBool :: Num a => Bool -> MyMath a

我在这里没有看到任何布尔值。谢谢don,在发布这个问题时,我忘了将我同时所做的更改调整到所有必要的位置-现在应该更清楚了。请注意,不应该使用数据上下文。它被认为是一种不合适的特性,在GHC的较新版本中被弃用。GADT更加灵活。存在量化的问题是我不能使用像“(Num n)=someFunction”这样的模式绑定——编译器刚刚抱怨过。当然可以。您只需假设
n
是某个未知的
Num
typeclass实例。如果您仍然存在问题,只需向我们展示基于此方法的不起作用的代码。虽然您可以修复此特定错误,但您很快就会发现存在类型对您的问题毫无用处。让我们暂时不考虑
/
不是
Num
的一部分这一事实,而是使用
+
,我还将使用上面代码中的
l
r
l+r
有意义吗?我们知道,对于某些类型的
a
r::Num b=>b
,l::Num a=>a
<代码>+
要求其参数具有相同的类型,但我们不知道这一点
a
很可能是一个
Int
b
可能是一个
Float
!您应该摆脱存在的量化,而是公开其中数字的类型。GADT代码的修复应该很简单:
数据MyMathExpr a where…
MyMathVal
也是如此。好的,我想我在读了这篇文章之后终于得到了数据定义:。但现在编译器告诉我,当我试图进行模式匹配时,我在做一些愚蠢的事情(请看我更新的帖子)。