代码之家  ›  专栏  ›  技术社区  ›  Paige Ruten

这个haskell函数的类型签名是什么?

  •  4
  • Paige Ruten  · 技术社区  · 16 年前

    我编写了一个函数来检查一个数字是否是质数:

    prime n = prime' n 2 (floor (sqrt n))
         where prime' n c u | n `mod` c == 0 = False
                            | c > u = True
                            | otherwise = prime' n (c+1) u
    

    我不知道这个函数的类型签名应该是什么。起初我认为应该是这样:

    prime :: Integral a => a -> Bool
    

    但编译时会出错,因为 sqrt 期望A Floating a floor 期望A RealFrac a 而不是 Integral a . 当我删除类型签名时,它会编译,但函数不工作:

    *Euler> :t prime
    prime :: (Integral a, RealFrac a, Floating a) => a -> Bool
    *Euler> prime 5
    
    <interactive>:1:0:
        Ambiguous type variable `t' in the constraints:
          `Floating t' arising from a use of `prime' at <interactive>:1:0-6
          `RealFrac t' arising from a use of `prime' at <interactive>:1:0-6
          `Integral t' arising from a use of `prime' at <interactive>:1:0-6
        Probable fix: add a type signature that fixes these type variable(s)
    

    我怎样才能使这个功能工作?

    4 回复  |  直到 16 年前
        1
  •  12
  •   newacct    16 年前

    问题是你用的 sqrt n 哪种力量 n 是一个浮点数;您还可以使用 mod n ,强制n为整数。从直观上看,从代码来看, n 应该 是整数,因此不能直接调用 平方正交函数 关于它。相反,你可以使用 fromIntegral 把它从一个整数转换成另一个数字类型。

    prime :: (Integral a) => a -> Bool
    prime n = prime' n 2 (floor (sqrt (fromIntegral n)))
         where prime' n c u | n `mod` c == 0 = False
                            | c > u = True
                            | otherwise = prime' n (c+1) u
    
        2
  •  3
  •   ephemient    16 年前

    只想回顾一下其他答案没有涉及到的最后一点…

    *Euler> :t prime
    prime :: (Integral a, RealFrac a, Floating a) => a -> Bool
    

    类型检查器推断 prime 不能接受类型为的参数 a 只要 是的实例 Integral , RealFrac Floating 同时上课。

    *Euler> prime 5
    
    <interactive>:1:0:
        Ambiguous type variable `t' in the constraints:
          `Floating t' arising from a use of `prime' at <interactive>:1:0-6
          `RealFrac t' arising from a use of `prime' at <interactive>:1:0-6
          `Integral t' arising from a use of `prime' at <interactive>:1:0-6
        Probable fix: add a type signature that fixes these type variable(s)
    

    当你要求的时候 prime 5 但是,它抱怨没有任何默认类型的 5 可以满足这些条件。

    你很有可能自己写

    instance (Integral a, RealFrac b, Floating b) => Integral (Either a b) where ...
    instance (Integral a, RealFrac b, Floating b) => RealFrac (Either a b) where ...
    instance (Integral a, RealFrac b, Floating b) => Floating (Either a b) where ...
    

    (你还得加上 Num , Ord , Real , Fractional 等实例),然后 素数5 是可以接受的,因为 5 :: Either Integer Float 它确实满足类型条件。

        3
  •  3
  •   Arjun Guha    16 年前

    或者,您可以更改上限测试:

    prime n = prime' n 2
        where prime' n c | n `mod` c == 0 = False
                         | c * c > n = True
                         | otherwise = prime' n (c+1)
    

    顺便说一句,你不需要 n 作为一个论点 prime' 因为它在所有调用中都是常量。

        4
  •  2
  •   Ashutosh Mehra    16 年前

    你可以改变 (sqrt n) (sqrt (fromInteger n)) 使功能按预期工作。这是必需的,因为 sqrt 是:

    sqrt :: (Floating a) => a -> a
    

    例如,这样做是错误的:

    sqrt (2 :: Int)