【问题标题】:Haskell length list + factorialHaskell 长度列表 + 阶乘
【发布时间】:2019-10-07 16:02:44
【问题描述】:

我对 Haskell 很陌生。我一直在尝试实现n_choose_r,但由于某种原因,我的阶乘函数返回了奇怪的值。

Main.hs

factorial 0 = 1
factorial n = n * factorial (n-1)

subsets k list = factorial n where
    n = length list

一些不同的情况

> subsets 3 [1..4]
24 // correct value
> factorial 60
8320987112741390144276341183223364380754172606361245952449277696409600000000000000
> subsets 3 [1..60]
-8718968878589280256 // wrong value
> subsets 3 [1..100]
0 // wrong value

列表越长,数字似乎就越不稳定。谁能解释一下?

【问题讨论】:

    标签: haskell integer-overflow


    【解决方案1】:

    您的factorial 函数是多态的:它的类型为(Eq p, Num p) => p -> p。当您像 factorial 60 一样调用它时,p 会被实例化为 Integer(这种选择称为“类型默认”),它是任意精度的并且没有上限。然而,length 在其输出中不是多态的:它总是返回一个Int。 Haskell 不会为您自动在数字类型之间进行转换,因此当您使用length 的结果调用factorial 时,它也使用Int,它确实有一个上限,在您的情况下似乎是@987654331 @(您可以通过 maxBound :: Int 进行验证)。要解决此问题,您可以自己将 Int 转换为 Integer:

    subsets k list = factorial (toInteger n) where
        n = length list
    

    或使用genericLength,它与length 相同,只是它的输出类型是多态的:

    import Data.List
    
    subsets k list = factorial n where
        n = genericLength list
    

    请注意,如果您使用后一个选项,则需要注意不要做任何其他会强制使用Int 而不是默认为Integer 的事情。

    【讨论】:

    • 啊,明白了。非常感谢!我没有意识到 Int 和 Integer 之间有区别。刚查了一下,发现不一样了。你是救生员??
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多