Haskell长度列表+阶乘

问题描述 投票:2回答:1

我对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个回答
3
投票

您的factorial函数是多态的:其类型为(Eq p, Num p) => p -> p。当像factorial 60那样调用它时,p被实例化为Integer(此选择称为“类型默认值”),它是任意精度的,没有上限。但是,length在其输出中不是多态的:它总是返回Int。 Haskell不会自动为您在数字类型之间转换,因此当您以factorial的结果调用length时,它也会使用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

© www.soinside.com 2019 - 2024. All rights reserved.