Haskell 类型错误`map (\idx -> (2.400 ** idx)/fact idx) [0..9]` `fact :: Int ->Int`,预期的整数,实际的双精度 [英] Haskell type error `map (\idx -> (2.400 ** idx) / fact idx) [0..9]` `fact :: Int -> Int`, Expected Int, Actual Double
问题描述
在解决下面这个问题时,我遇到了一个奇怪的错误.
module Main where事实 :: Int ->整数事实 0 = 1事实 n = foldr (*) 1 [1..n]calc_e_to_power :: 双 ->双倍的calc_e_to_power x = foldr (+) 0 $ map (\idx -> (x ** idx)/fact idx) [0..9]主要:: IO()主要 = 做putStrLn $ 显示 $ calc_e_to_power 2.4000
我收到 fact
函数的类型错误,该函数表示预期的 Int
,得到 Double
.在这里idx
的类型怎么可能是Double.
我知道 **
会将除法的第一个表达式的类型转换为 Double,但是 2.3243/3
在 ghci 中工作得很好.当我删除 fact
的类型签名时,它符合并且完美运行.
不太确定我在这里遗漏了什么.
我还在 Repl 中重新创建了示例.有人能帮我理解这里有什么问题吗?
repl 上的代码链接 https://replit.com/@VipulSharma12/HeavyGrandioseCrypto#src/Main.hs
在你的表达中:
map (\idx -> (x ** idx)/fact idx) [0..9]
fact
需要一个 Int
并返回一个 Int
,所以 idx
应该是一个 Int
和 fact idx
也是一个 Int
.但这与 (**)
被定义为 (**) :: 浮动 a =>->->a
接受两个相同类型的元素,它们应该是 Floating
类型类的成员.
特别是因为 x
的类型是 Double
,因此 x ** idx
将是 Double
同样,这要求 idx
是 Double
.但是idx
应该是fact idx
的Int
,一个项目不能是Int
和>双倍
同时.
我们可以做的是使用 (^) :: (Num a, Integral b) =>->b->a
接受 b
类型的项作为第二个操作数,这样 b
是 Integral
类型类,当 b
是 Int
时就是这种情况.
现在分子 x ^ idx
的类型为 Double
(因为 (^)
的类型为 (^) :: (Num a, Integral b) => a -> b -> a
而 fact idx
的类型为 Int
.我们不能划分 >Double
由 Int
,因为 (/) :: 分数 a => a -> a -> a
需要两个操作数具有相同的类型,并且该类型应该是 Fractional
类型类的成员(并且 Int
不是该类型类的成员).
我们可以使用 fromIntegral:: (Integral a, Num b) =>->b
转换一个 Integral
数字(Int
是 Integral
类型类的成员),到任何类型 b
其中 b
是 Num
类型类的成员(并且 Double
是此类型类的成员).
因此我们可以修复表达式并将其重写为:
calc_e_to_power :: Double ->双倍的calc_e_to_power x = foldr (+) 0 $ map (\idx -> (x ^ idx)/fromIntegral (fact idx)) [0..9]代码>
我们可以使用 sum:: (Foldable f, Num a) =>f a ->a
避免使用 foldr
编写该部分:
calc_e_to_power :: Double ->双倍的calc_e_to_power x = sum (map (\idx -> (x ^ idx)/fromIntegral (fact idx)) [0..9])
预>While working on this problem below, I am getting a strange error.
module Main where fact :: Int -> Int fact 0 = 1 fact n = foldr (*) 1 [1..n] calc_e_to_power :: Double -> Double calc_e_to_power x = foldr (+) 0 $ map (\idx -> (x ** idx) / fact idx) [0..9] main :: IO () main = do putStrLn $ show $ calc_e_to_power 2.4000
I am getting type error for
fact
function which says expectedInt
, gotDouble
. How can the type ofidx
be Double here.I am aware that
**
will convert the type of first expression of division to Double, but2.3243 / 3
works perfectly fine in ghci. When I remove the type signature offact
, it complies and works perfectly.Not really sure what am I missing here.
I have also recreated the example in Repl. Can someone help me understand what's wrong here ?
Link to Code on repl https://replit.com/@VipulSharma12/HeavyGrandioseCrypto#src/Main.hs
解决方案In your expression:
map (\idx -> (x ** idx) / fact idx) [0..9]
fact
expects anInt
and returns anInt
, soidx
should be anInt
andfact idx
is also anInt
. But this clashes with the fact that(**)
is defined as(**) :: Floating a => a -> a -> a
takes two items of the same type that should be members of theFloating
typeclass.Especially since the type of
x
isDouble
, and thusx ** idx
will be aDouble
as well, this requiresidx
to be aDouble
. Butidx
should be anInt
for thefact idx
, and an item can not be anInt
andDouble
at the same time.What we can do is work with
(^) :: (Num a, Integral b) => a -> b -> a
which accepts as second operand an item of typeb
such thatb
is a member of theIntegral
typeclass, which is the case whenb
is anInt
.Now the numerator
x ^ idx
will have typeDouble
(since(^)
has type(^) :: (Num a, Integral b) => a -> b -> a
whereasfact idx
has typeInt
. We can not divide aDouble
by anInt
, since(/) :: Fractional a => a -> a -> a
requires both operands to have the same type, and that type should be a member of theFractional
typeclass (and anInt
is not a member of this typeclass).We can work with
fromIntegral :: (Integral a, Num b) => a -> b
to convert anIntegral
number (Int
is a member of theIntegral
typeclass), to any typeb
whereb
is a member of theNum
typeclass (andDouble
is a member of this typeclass).We thus can fix the expression and rewrite this to:
calc_e_to_power :: Double -> Double calc_e_to_power x = foldr (+) 0 $ map (\idx -> (x ^ idx) / fromIntegral (fact idx)) [0..9]
We can work with
sum :: (Foldable f, Num a) => f a -> a
to avoid writing that part withfoldr
:calc_e_to_power :: Double -> Double calc_e_to_power x = sum (map (\idx -> (x ^ idx) / fromIntegral (fact idx)) [0..9])
这篇关于Haskell 类型错误`map (\idx -> (2.400 ** idx)/fact idx) [0..9]` `fact :: Int ->Int`,预期的整数,实际的双精度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!