3

一般的な数値または除算構造のいずれかである新しい抽象データ型を定義したいと思います。Haskellでそれをどのように行うのですか?

私の最初のアプローチは次のとおりです。

data MyMath = MyNum Num
            | Div MyMath MyMath

問題は、コンパイラがデータ型ではなく型クラスである「Num」について文句を言うことです。したがって、私の2番目の考えは、次のような問題を解決することです。

data MyMath = MyNum Int
            | MyNum Float
            | Div MyMath MyMath

ただし、MyNumが2回使用されるため、これも機能しません。これは許可されていません。さらに、このアプローチは実際には多型ではありません。では、この問題の解決策は何ですか?

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'にも当てはまります。私には見えない愚かな間違いだと思います。あなたは?

4

4 に答える 4

3

これにより、コードで対処している問題は解決されますが、ブール値はカバーされません。データ宣言でクラス制約を使用する場合は、他の関数の場合と同じように使用します。

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

于 2012-05-11T14:49:33.597 に答える
3

そのために存在記号を使用できます。

> let data MyMath = forall n. Num n => MyNum n
> :t MyNum 3
MyNum 3 :: MyMath
> :t MyNum 3.5
MyNum 3.5 :: MyMath
于 2012-05-11T14:50:21.060 に答える
1

それを行うには多くの方法があります。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
于 2012-05-11T17:28:55.697 に答える
0

すでに述べたように、あなたの試みにはブール値は含まれていませんが、代わりにあなたの質問のテキストを使用します。

このタイプを発明する必要はありません。プレリュードのどちらかをチェックしてください。したがって、探しているのは、のインスタンスにEither a Boolなりたい場所です。これを実際に実施したい場合は、以下の編集の準備をしてください。aNum

編集:使用したくない場合はEither、を行うことができますdata MyMath a = MyNum a | MyBool Bool。これで、必要に応じてインスタンスになるように強制できますが、最初にこのSOの質問その回答を検討することをお勧めします。データ型のインスタンスを強制する必要は実際にはありません。intseadを使用する関数に対してそれを実行するだけです。aNum

于 2012-05-11T14:44:18.957 に答える