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)
考虑以下代码:
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中使用它,我建议让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