为什么在ghci中我可以输入:
5.0 * (3 - 1)
> 10.0
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试在.hs文件中创建一个函数并将其加载到:
test :: Float -> Int -> Int -> Float
test a b c = a * (b - c)
Run Code Online (Sandbox Code Playgroud)
我遇到了错误?"无法将预期类型'Float'与推断类型'Int'匹配?我如何编写一个函数,它接受一个浮点和2个整数参数并对它们执行上述操作?
我正在使用ghci v6.12.1,如果这有所作为...
Ben*_*Ben 38
数字文字(即只是在Haskell代码中键入数字)不是某种固定类型.它们是多态的.它们需要在某些需要具有特定类型的上下文中进行评估.
所以表达式5.0 * (3 - 1)是不是乘以一个Int通过Float.5.0必须是某种Fractional类型,3并且1每种都是某种Num类型.3 - 1意味着3和1都必须是相同的 Num类型,但我们仍然没有(还)对它是哪个特定的约束; 减法的结果是相同的类型.
*两个参数的均值必须是相同的类型,结果也是相同的类型.由于5.0是某种Fractional类型,(3 - 1)必须也是.我们已经知道了3,1并且(3 - 1)必须是某种Num类型,但所有Fractional类型都是Num类型,因此这些要求不会发生冲突.
最终的结果是,整个表达式5.0 * (3 - 1)是某种类型的即Fractional,和5.0,3和1都是相同的类型.您可以:t在GHCi中使用该命令来查看:
Prelude> :t 5.0 * (3 - 1)
5.0 * (3 - 1) :: Fractional a => a
Run Code Online (Sandbox Code Playgroud)
但要实际评估该表达式,我们需要针对某种具体类型进行评估.如果我们正在评估这一点,并把它传递给一些功能要求Float,Double或其他一些特定的Fractional类型,然后哈斯克尔会选那一个.如果我们只是评估表达式而没有其他上下文要求它是一个特定的类型,Haskell有一些默认规则来自动为你选择一个(如果默认规则不适用它将改为给你一个关于模糊类型变量的类型错误).
Prelude> 5.0 * (3 - 1)
10.0
Prelude> :t it
it :: Double
Run Code Online (Sandbox Code Playgroud)
在我评估之上5.0 * (3 - 1),然后询问itGHCi总是绑定到它评估的最后一个值的魔术变量的类型.这告诉我GHCi默认我的Fractional a => a类型Double,以便计算表达式的值10.0.在这样做的评估,它永远只能multipled(和减去)DoubleS,它从来没有一个乘Double用Int.
现在,当您尝试多个看起来可能属于不同类型的数字文字时,这就是正在发生的事情.但是你的test函数不是文字的倍增,它是特定已知类型的倍增变量.在Haskell中,你不能将Inta 乘以a,Float因为*运算符具有类型Num a => a -> a -> a- 它采用相同数值类型的两个值,并为您提供该类型的结果.你可以乘一个Int由Int获得的Int,或Float由Float获得Float.你不能乘以Inta Float得到a ???.
其他语言仅在某些情况下通过隐式插入对转换函数的调用来支持此类操作.Haskell 从不在类型之间隐式转换,但它具有转换函数.如果要调用它们,您只需要显式调用它们.这样可以解决问题:
test :: Float -> Int -> Int -> Float
test a b c = a * fromIntegral (b - c)
Run Code Online (Sandbox Code Playgroud)
请尝试以下操作:
test :: Float -> Int -> Int -> Float
test a b c = a * fromIntegral (b - c)
Run Code Online (Sandbox Code Playgroud)
为什么这样做?
b和c都是Ints,所以表达式(b - c)也是Int。(*)是Num a => a -> a -> a。ais 的类型FloatHaskell 更新了(a*)to的类型签名Float -> Float。(b - c)是Int和不是Float,如果你想这样做的Haskell会抱怨a * (b - c)。fromIntegral是(Integral a, Num b) => a -> b。fromIntegral (b - c)是Num b => b。Float是 typeclass 的一个实例,Num您可以这样做,a * fromIntegral (b - c)因为类型签名(*)是Num a => a -> a -> a。test评估为Float。希望这有帮助。
| 归档时间: |
|
| 查看次数: |
14763 次 |
| 最近记录: |