使函数的类型取决于输入

时间:2015-09-15 20:16:25

标签: function haskell if-statement types

所以我注意到在n = 20之后,LearnYouAHaskell(下面)中给出的阶乘函数因为Int类型的有限工作范围而缩小。

factorial :: Int -> Int
factorial 0 = 1
factorial n * factorial (n-1)

使用factorial :: Integer -> Integer很好地解决了这个问题,但它让人想起了这个问题。据说整数比Int稍微慢一点(我知道我在这里捏便士)我希望我的阶乘函数只在输入大于20时才使用Integer并保留Int->Int类型数量较少。似乎应该有一个优雅的解决方案,使用if-then-else或警卫,但继续运行语法胡椒(错误消息)

4 个答案:

答案 0 :(得分:11)

你可以在没有依赖类型的情况下制作一个hackish解决方案,使用sum类型并在需要时增长,或者在某些情况下将转换延迟到Integer直到结束。我不希望任何解决方案都比使用Integer更好 - 不要害怕整数,gmp和mpir都很好。

铸造解决方案类似于:

selectiveFactorial :: Integer -> Integer
selectiveFactorial i
    | i < 20 = fromIntegral $ factorial (fromIntegral i :: Int)
    | otherwise = factorial i

factorial :: Integral a => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

答案 1 :(得分:7)

作为Rein Henrichs said你可以用依赖类型的语言来做这些事情,Haskell没有(但是,相当)具有。比如伊德里斯,它看起来像

factorial : (n : Int) -> if n <= 20 then Int else Integer
factorial n with (n <= 20)
  factorial n | True = thisfactorial n
  factorial n | False = thatfactorial n

但是你将如何使用这个结果?好吧,你需要进行比较,找出所期望的类型,一旦说完了,我就不知道你是怎么赢的。为了完整起见,使用网站看起来像这样:

use : Int -> Integer
use n with (factorial n)
  use n | fn with (n <= 20)
    use n | fn | False = fn
    use n | fn | True = cast fn

请注意with条款的顺序非常重要! fn绑定获取类型if n <= 20 then Int else Integer;由于我不完全理解的原因,n <= 20测试必须在右边,以便模式匹配影响其类型。

答案 2 :(得分:5)

无法完成。但是你可以做些事情:

  1. 使类型更通用:factorial :: Num a => a -> a; 这允许您的函数的用户决定他想要发生什么运行时惩罚以及允许的数字范围。

  2. 使用类似data PossiblyBig = Small Int | Big Integer的和类型,然后有一个实现instance Num PossiblyBig,它将符合Int的内容编码为Small,以及不需要&#的内容39; t适合Big; AFAIK Integer已经像这样工作(如果你想确切知道,请查看GMP实现),所以这更像是一个典型的例子,而不是在这种特殊情况下应该做什么的建议。

答案 3 :(得分:1)

使函数的类型取决于它的值正是dependent types的用途。不幸的是,Haskell没有依赖类型,因此无法做到这一点。