编辑:@Downvoters: 你能否至少告诉我如何改进这个问题?我尽我所能,并且在没有任何评论的情况下获得投票并不符合我的意见。
我仍然是Haskell的新手,作为练习,我试图创建函数,它返回n
的连续分数展开的第一个x
项。第一个参数x
可以是浮点数或积分,第二个参数必须是int
。到目前为止,这是我的代码,加载时没有错误:
continuedFraction x n | x < 0 = []
| n < 1 = []
| otherwise = [floor x] ++ (take n (continuedFraction (1 / (x - floor x)) (n-1) ) )
(我知道这不是很优雅,但这是我在那时能够提出的最简单的。)
一旦我实际使用该功能,例如continuedFraction 3.1415 4
我收到以下错误消息。任何人都可以指出我的错误/解释那条消息吗?
(我确实尝试使用上述想法制作类型定义,但也没有成功:continuedFraction :: (Num x) => x -> Int -> [Integer]
)
错误消息(在没有类型定义的情况下运行时):
*Main> continuedFraction 3.1415 4
<interactive>:86:1:
Could not deduce (Integral a0)
arising from a use of `continuedFraction'
from the context (Integral t)
bound by the inferred type of it :: Integral t => [t]
at <interactive>:86:1-26
The type variable `a0' is ambiguous
Note: there are several potential instances:
instance Integral Integer -- Defined in `GHC.Real'
instance Integral Int -- Defined in `GHC.Real'
instance Integral Word -- Defined in `GHC.Real'
In the expression: continuedFraction 3.1415 4
In an equation for `it': it = continuedFraction 3.1415 4
<interactive>:86:19:
Could not deduce (Fractional a0) arising from the literal `3.1415'
from the context (Integral t)
bound by the inferred type of it :: Integral t => [t]
at <interactive>:86:1-26
The type variable `a0' is ambiguous
Note: there are several potential instances:
instance Integral a => Fractional (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
instance Fractional Double -- Defined in `GHC.Float'
instance Fractional Float -- Defined in `GHC.Float'
In the first argument of `continuedFraction', namely `3.1415'
In the expression: continuedFraction 3.1415 4
In an equation for `it': it = continuedFraction 3.1415 4
答案 0 :(得分:3)
如果你是Haskell的初学者,你应该坚持一些规则:
Double
Fractional a
-XScopedTypeVariables
和ghci来探索编译器将推断的签名,以了解类型类现在让我们探索你的功能 - 你想要生成一个连续的分数我假设你写下来的公式是为了生成它是正确的。 Haskell足以模拟无限列表,因此让我们使用该功能并摆脱第二个参数并生成(可能)无限列表。
continuedFraction :: Double -> [Int]
所以我们看到 - 你期待一个Double
输入,结果是[Int]
,即整数列表,为了简单起见我选择了Int
,就像巨大的Integer
一样我不认为这个算法既不稳定也不高效 - 并且使用Double
我认为真正的问题是浮点算术。
continued fraction x | x < 0 = []
| otherwise = let i = floor x
x' = 1/(x - fromIntegral i)
in i : continuedFraction x'
这是您提出的最简单的解决方案,您遇到的问题
i :: Int
,x :: Double
你不能减去不同类型的东西,没有自动装箱/自动强制。我们喜欢对这些事情的控制 - 编译器不足够聪明,无法推断我们“显然”想要计算的内容(如果使用MS Excel,您会看到这会导致什么)。
此问题的解决方案是在这种情况下显式转换fromIntegral :: Double -> Int
为了便于阅读我还将[a] ++
切换为a :
这是相同的,更少写入和更高性能,但性能不在此处
现在使用ghci中的函数:ghci myfile.hs
> continuedFraction 3.1415
[3,.....] --infinite list
> take 4 $ continuedFraction 3.1415
[3,7,14,1]
现在你可以探索这个功能了!
{-# LANGUAGE ScopedTypeVariables#-}
module SO34830462 where
--continuedFraction :: Double -> [Int]
continuedFraction :: Double -> _
continuedFraction x | x < 0 = []
| otherwise = let i = floor x
x' = 1/ (x - fromIntegral i)
in i : continuedFraction x'
ghci myfile.hs
会导致错误
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling SO34830462 ( 34830462.hs, interpreted )
myfile.hs:6:32:
Found hole ‘_’ with type: [t]
[...]
continuedFraction :: Integral t => Double -> [t]
[...]
Failed, modules loaded: none.
它简单地告诉你 - “哦,你没有指定正确的类型签名”,但是ghc可以使用这种类型的签名。
您可以替换类型签名并对Double
参数执行相同操作,逐位探索函数。
如果您不确定从什么开始,可以省略类型签名,并在:t continuedFraction
旁边调用ghci会话。
答案 1 :(得分:2)
Haskell数字塔再次袭来。太一般了!然而,这种迟钝的错误信息!
continuedFraction x n
| x < 0 || n < 1 =
[]
| otherwise =
floor x : take n (continuedFraction (1 / (x - floor x)) (n - 1))
因此,如果您将此代码放入解释器,然后推断出您获得的类型
continuedFraction
:: (Integral a, Integral t, RealFrac a) => a -> Int -> [t]
这里有一个隐藏的问题!没有好办法解决这两个Integral a, RealFrac a
约束。
λ> :info Integral
class (Real a, Enum a) => Integral a where
...
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
λ> :info RealFrac
class (Real a, Fractional a) => RealFrac a where
...
instance RealFrac Float -- Defined in ‘GHC.Float’
instance RealFrac Double -- Defined in ‘GHC.Float’
按定义,积分类型不是小数类型;根据定义,分数类型不是整数类型。当然,有两种方法可以在两者之间进行转换,但这里没有调用。 GHC的错误消息的迟钝掩盖了这个问题。
问题出现在这个表达式上:x - floor x
。 floor x
具有整数类型,x
具有小数类型。为了(-) :: (Num a) => a -> a -> a
进行类型检查,我们得到了不可能的(Integral a, RealFrac a)
约束。
解决方案是使用floor x
提升fromInteger :: Num a => Integer -> a
。
continuedFraction' :: (Integral t, RealFrac a) => a -> Int -> [t]
continuedFraction' x n
| x < 0 || n < 1 =
[]
| otherwise =
floor x : take n (continuedFraction' (1 / decimal) (n - 1))
where
decimal = x - fromInteger (floor x)
λ> continuedFraction' 3.14159 4
[3,7,15,1]