我有
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
答案 0 :(得分:13)
有一个函数fromIntegral,它将整数转换为任何其他数字类型。所以你可以这样做:
result :: (Integral n, Num m) => n -> m -> m
result val coefficient = fromIntegral val * coefficient
或者,以无点样式:
result = (*) . fromIntegral
考虑以下代码:
coefficient :: (Num a) => a
coefficient = 1.0
这本身无效,如下所示。因为1.0是分数(不是整数)的文字,所以GHC只能将其编码为能够表示分数的任何类型(forall a。分数a => a)。但是,您已指定它必须对任何数字类型有效(forall a。Num a => a)。某些数字类型(例如Integer)不能表示小数值,并且不是Fractional的实例(正确地说是这样),因此不能进行类型检查。您可以按如下方式解决此问题:
coefficient :: (Fractional a) => a
coefficient = 2.0
这里GHC可以推断出类型,系数工作正常。值得注意的是,Fractional是Num的子类,所以作为Fractional的所有东西也必须是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中使用它,我建议让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
我们不想要的(这是因为类型注释引用了lambda表达式的值,而不是结果的声明)。我不知道如何让显式类型在这里工作,所以也许比我们更有知识的人可以回答:P