Haskell 类型错误 `map (\idx -> (2.400 ** idx) / fact idx) [0..9]` `fact :: Int -> Int`,预期 Int,实际 Double
Haskell type error `map (\idx -> (2.400 ** idx) / fact idx) [0..9]` `fact :: Int -> Int`, Expected Int, Actual Double
在解决下面这个问题时,我遇到了一个奇怪的错误。
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
我收到 fact
函数的类型错误,它说期望 Int
,得到 Double
。这里idx
的类型怎么可能是Double。
我知道 **
会将第一个除法表达式的类型转换为 Double,但是 2.3243 / 3
在 ghci 中工作得很好。当我删除 fact
的类型签名时,它符合要求并完美运行。
不太确定我在这里遗漏了什么。
我还在 Repl 中重新创建了示例。有人可以帮助我了解这里出了什么问题吗?
Link 到 repl 上的代码 https://replit.com/@VipulSharma12/HeavyGrandioseCrypto#src/Main.hs
在你的表达中:
map (\idx -> (x ** idx) / fact idx) [0..9]
fact
期望 Int
和 returns 一个 Int
,因此 idx
应该是 Int
和 fact idx
也是一个Int
。但这与 (**)
被定义为 (**) :: Floating a => a -> a -> a
需要两个相同类型的项目相冲突,这两个项目应该是 Floating
类型类的成员。
特别是因为 x
的类型是 Double
,因此 x ** idx
也将是 Double
,这需要 idx
是Double
。但是 idx
应该是 fact idx
的 Int
,一个项目不能同时是 Int
和 Double
。
我们可以做的是使用 (^) :: (Num a, Integral b) => a -> b -> a
,它接受类型为 b
的项目作为第二个操作数,这样 b
是 Integral
类型类的成员,当 b
是 Int
.
时就是这种情况
现在分子 x ^ idx
的类型为 Double
(因为 (^)
的类型为 (^) :: (Num a, Integral b) => a -> b -> a
而 fact idx
的类型为 Int
。我们不能将 Double
除以 Int
,因为 (/) :: Fractional a => a -> a -> a
要求两个操作数具有相同的类型,并且该类型应该是 Fractional
类型类的成员(并且Int
是 不是 此类型类的成员)。
我们可以使用 fromIntegral :: (Integral a, Num b) => a -> b
将 Integral
数字(Int
是 Integral
类型类的成员)转换为任何类型 b
其中 b
是 Num
类型类的成员(并且 Double
是该类型类的成员)。
因此我们可以修复表达式并将其重写为:
calc_e_to_power :: Double -> Double
calc_e_to_power x = foldr (+) 0 $ map (\idx -> (x <strong>^</strong> idx) / <strong>fromIntegral</strong> (fact idx)) [0..9]
我们可以使用 sum :: (Foldable f, Num a) => f a -> a
来避免用 foldr
编写那部分:
calc_e_to_power :: Double -> Double
calc_e_to_power x = <b>sum</b> (map (\idx -> (x <strong>^</strong> idx) / fromIntegral (fact idx)) [0..9])
在解决下面这个问题时,我遇到了一个奇怪的错误。
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
我收到 fact
函数的类型错误,它说期望 Int
,得到 Double
。这里idx
的类型怎么可能是Double。
我知道 **
会将第一个除法表达式的类型转换为 Double,但是 2.3243 / 3
在 ghci 中工作得很好。当我删除 fact
的类型签名时,它符合要求并完美运行。
不太确定我在这里遗漏了什么。
我还在 Repl 中重新创建了示例。有人可以帮助我了解这里出了什么问题吗?
Link 到 repl 上的代码 https://replit.com/@VipulSharma12/HeavyGrandioseCrypto#src/Main.hs
在你的表达中:
map (\idx -> (x ** idx) / fact idx) [0..9]
fact
期望 Int
和 returns 一个 Int
,因此 idx
应该是 Int
和 fact idx
也是一个Int
。但这与 (**)
被定义为 (**) :: Floating a => a -> a -> a
需要两个相同类型的项目相冲突,这两个项目应该是 Floating
类型类的成员。
特别是因为 x
的类型是 Double
,因此 x ** idx
也将是 Double
,这需要 idx
是Double
。但是 idx
应该是 fact idx
的 Int
,一个项目不能同时是 Int
和 Double
。
我们可以做的是使用 (^) :: (Num a, Integral b) => a -> b -> a
,它接受类型为 b
的项目作为第二个操作数,这样 b
是 Integral
类型类的成员,当 b
是 Int
.
现在分子 x ^ idx
的类型为 Double
(因为 (^)
的类型为 (^) :: (Num a, Integral b) => a -> b -> a
而 fact idx
的类型为 Int
。我们不能将 Double
除以 Int
,因为 (/) :: Fractional a => a -> a -> a
要求两个操作数具有相同的类型,并且该类型应该是 Fractional
类型类的成员(并且Int
是 不是 此类型类的成员)。
我们可以使用 fromIntegral :: (Integral a, Num b) => a -> b
将 Integral
数字(Int
是 Integral
类型类的成员)转换为任何类型 b
其中 b
是 Num
类型类的成员(并且 Double
是该类型类的成员)。
因此我们可以修复表达式并将其重写为:
calc_e_to_power :: Double -> Double
calc_e_to_power x = foldr (+) 0 $ map (\idx -> (x <strong>^</strong> idx) / <strong>fromIntegral</strong> (fact idx)) [0..9]
我们可以使用 sum :: (Foldable f, Num a) => f a -> a
来避免用 foldr
编写那部分:
calc_e_to_power :: Double -> Double
calc_e_to_power x = <b>sum</b> (map (\idx -> (x <strong>^</strong> idx) / fromIntegral (fact idx)) [0..9])