4

私は持っています

coefficient :: ???????
coefficient = 1.0

val :: Int

そして私はしたい

result :: ???????
result val coefficient = val * coefficient

これを機能させるには、どのタイプの署名と変換関数を実行する必要がありますか?valを任意の種類のNumに一般化する機能が必要な場合は、その上で何をする必要がありますか?

これ:

coefficient = 1.0

val :: Int
val = 3

result :: Num a => a
result = coefficient * (fromIntegral val)

このコンパイラの警告が表示されます:

Could not deduce (a ~ Double)
from the context (Num a)
  bound by the type signature for result :: Num a => a
  at Move.hs:17:1-41
  `a' is a rigid type variable bound by
      the type signature for result :: Num a => a at Move.hs:17:1
In the first argument of `(*)', namely `coefficient'
In the expression: coefficient * (fromIntegral val)
In an equation for `result':
    result = coefficient * (fromIntegral val)

私はそれが私が最初に尋ねたものではないことを知っています、私は私のコードをサニタイズするときにいくつかの間違いをしました。

係数のタイプがあります:

coefficient :: Num a => a
coefficient = 1.0

val :: Int
val = 3

result :: Num a => a
result = coefficient * (fromIntegral val)

結果のエラー:

Could not deduce (Fractional a) arising from the literal `1.0'
from the context (Num a)
  bound by the type signature for coefficient :: Num a => a
  at Move.hs:12:1-17
Possible fix:
  add (Fractional a) to the context of
    the type signature for coefficient :: Num a => a
In the expression: 1.0
In an equation for `coefficient': coefficient = 1.0
4

1 に答える 1

13

整数を他の数値タイプに変換する関数fromIntegralがあります。だからあなたはすることができます:

result :: (Integral n, Num m) => n -> m -> m
result val coefficient = fromIntegral val * coefficient

または、ポイントフリースタイルの場合:

result = (*) . fromIntegral

更新された質問に関する更新(@Drew)

このコードを考えてみましょう:

coefficient :: (Num a) => a
coefficient = 1.0

次のように、これ自体は無効です。1.0は小数(整数ではない)のリテラルであるため、GHCは、小数を表すことができる任意のタイプとしてのみエンコードできます(すべてのa。小数a => a)。ただし、すべての数値タイプに対して有効である必要があることを指定しました(すべてのa。num a => a)。一部の数値型(整数など)は小数値を表すことができず、小数のインスタンスではないため(当然のことながら)、これは型チェックできません。これは次のように修正できます。

coefficient :: (Fractional a) => a
coefficient = 2.0

ここでGHCはタイプを推測でき、係数は正常に機能します。分数はNumのサブクラスであるため、分数であるものはすべてNumである必要があることに注意してください。私の答えの最初の部分の関数を見ると、係数はNumタイプである必要があるだけなので((*)でのみ使用するため)、そのパラメーターの代わりにこの係数の定義を使用できます。あなたの問題はまったく同じ理由で発生します。

result :: (Num a) => a
result = coefficient * fromIntegral val

この場合も、この関数の結果は係数と同じタイプである必要があります。係数はNumタイプではなく、分数タイプであるため、これを次のように変更する必要があります。

result :: (Fractional a) => a
result = coefficient * fromIntegral val

そして、それはタイプチェックする必要があります。@singpolymaは、元のエラーの一部が単相制限に関係していたことは正しいですが、型シグネチャをもう少し具体的にする必要がありました。(Num a)=> aで動作させる場合、係数は整数(たとえば、1)である必要があります。

GHCiに関する最新情報(@Marcin)

これをGHCiで使用するには、GHCiにタイプを推測させることをお勧めします。この場合、(GHCiで)次のように入力します。

let result val coefficient = fromIntegral val * coefficient

次に、GHCiは結果のタイプを正しく推測します。':t'コマンドを使用して、GHCiに何かがどのタイプであると考えているかを尋ねることができます。

Prelude> :t result
result :: (Integral a1, Num a) => a1 -> a -> a

明示的な型アノテーションが必要な場合は、次のことができます。

let result = (\val coefficient -> fromIntegral val * coefficient) :: (Integral a, Num b) => a -> b -> b

明示的なタイプを試してみますが、GHCiはこれを単形にします:

Prelude> :t result
result :: Integer -> Integer -> Integer

これは望ましくありません(これは、型アノテーションが結果の宣言ではなく、ラムダ式の値を参照するためです)。ここでも明示的な型を機能させる方法がわからないので、私たちよりも知識のある人が答えることができます:P

于 2012-11-13T10:03:32.070 に答える