Haskell长度列表+;阶乘的

Haskell长度列表+;阶乘的,haskell,integer-overflow,Haskell,Integer Overflow,我对哈斯克尔很陌生。我一直在尝试实现n\u 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 832098711274139

我对哈斯克尔很陌生。我一直在尝试实现
n\u 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

似乎名单越长,数字就越不可靠。有人能解释吗?

你的
阶乘函数是多态的:它有type
(Eq p,Num p)=>p->p
。当您像
factorial 60
那样调用它时,
p
被实例化为
Integer
(此选项称为“type defaulting”),这是任意精度,没有上限。但是,
length
在其输出中不是多态的:它总是返回一个
Int
。Haskell不会自动为您在数字类型之间进行转换,因此当您使用
length
的结果调用
factorial
时,它也使用
Int
,它确实有一个上限,在您的情况下,这个上限似乎是
9223372036854775807
(您可以通过执行
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之间有区别。只是查了一下,发现了区别。你是救命恩人