Haskell乘以Int和实数

Dre*_*rew 4 int haskell types monomorphism-restriction real-datatype

我有

coefficient :: ???????
coefficient = 1.0
Run Code Online (Sandbox Code Playgroud)

val :: Int
Run Code Online (Sandbox Code Playgroud)

而且我想这样做

result :: ???????
result val coefficient = val * coefficient
Run Code Online (Sandbox Code Playgroud)

我需要做什么类型的签名和转换功能才能使其工作?如果我想有能力将val推广到任何类型的Num,我该怎么办呢?

这个:

coefficient = 1.0

val :: Int
val = 3

result :: Num a => a
result = coefficient * (fromIntegral val)
Run Code Online (Sandbox Code Playgroud)

给我这个编译器警告:

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)
Run Code Online (Sandbox Code Playgroud)

我知道那不是我原来的问题,我在清理代码时犯了一些错误.

现在有一个系数类型:

coefficient :: Num a => a
coefficient = 1.0

val :: Int
val = 3

result :: Num a => a
result = coefficient * (fromIntegral val)
Run Code Online (Sandbox Code Playgroud)

结果错误:

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
Run Code Online (Sandbox Code Playgroud)

小智 13

有一个函数fromIntegral,它将整数转换为任何其他数字类型.所以你可以这样做:

result :: (Integral n, Num m) => n -> m -> m
result val coefficient = fromIntegral val * coefficient
Run Code Online (Sandbox Code Playgroud)

或者,无点样式:

result = (*) . fromIntegral
Run Code Online (Sandbox Code Playgroud)

有关更新问题的更新(@Drew)

考虑以下代码:

coefficient :: (Num a) => a
coefficient = 1.0
Run Code Online (Sandbox Code Playgroud)

这本身无效,如下所示.因为1.0是小数(不是整数)的文字,所以GHC只能将其编码为能够表示小数的任何类型(forall a.分数a => a).但是,您已指定它必须对任何数字类型有效(forall a.Num a => a).某些数字类型(例如Integer)不能表示小数值,并且不是Fractional的实例(正确地说是这样),因此不能进行类型检查.您可以按如下方式解决此问题:

coefficient :: (Fractional a) => a
coefficient = 2.0
Run Code Online (Sandbox Code Playgroud)

这里GHC可以推断出类型,系数工作正常.值得注意的是,Fractional是Num的子类,所以作为Fractional的所有东西也必须是Num.如果我们在我的答案的第一部分中查看函数,系数只需要是一个Num类型(因为我们只将它与(*)一起使用),所以我们可以使用这个系数定义来代替那个参数.出于同样的原因,您的问题就出现了.

result :: (Num a) => a
result = coefficient * fromIntegral val
Run Code Online (Sandbox Code Playgroud)

同样,此函数的结果必须与系数的类型相同.由于系数不能是任何Num类型,而只是一个小数类型,我们需要将其更改为:

result :: (Fractional a) => a
result = coefficient * fromIntegral val
Run Code Online (Sandbox Code Playgroud)

然后那应该是typecheck.@singpolyma是正确的,你的原始错误部分与单同性限制有关,但你只需要使类型签名稍微具体一些.如果你想使用(Num a)=> a,那么系数必须是整数(例如1).

关于GHCi的更新(@Marcin)

为了在GHCi中使用它,我建议让GHCi推断出这种类型.如果在这种情况下你键入(在GHCi中):

let result val coefficient = fromIntegral val * coefficient
Run Code Online (Sandbox Code Playgroud)

然后GHCi将正确推断结果的类型.您可以使用':t'命令询问GHCi它认为是什么类型的东西:

Prelude> :t result
result :: (Integral a1, Num a) => a1 -> a -> a
Run Code Online (Sandbox Code Playgroud)

如果您必须具有显式类型签名,则可以执行以下操作:

let result = (\val coefficient -> fromIntegral val * coefficient) :: (Integral a, Num b) => a -> b -> b
Run Code Online (Sandbox Code Playgroud)

要尝试拥有一个显式类型,但GHCi将使这个单态:

Prelude> :t result
result :: Integer -> Integer -> Integer
Run Code Online (Sandbox Code Playgroud)

我们不想要的(这是因为类型注释引用了lambda表达式的值,而不是结果的声明).我不知道如何让显式类型在这里工作,所以也许比我们更有知识的人可以回答:P