在Haskell中输入双打问题

时间:2013-07-03 18:53:43

标签: haskell types ghci

我想实现这笔钱。我遇到了关于类型签名的问题。

image

这就是Haskell的样子。

crowdWrong :: (Fractional b, Integral b) => b -> b
crowdWrong m = crowdWrong' m m

crowdWrong' :: (Fractional b, Integral b) => b -> b -> b
crowdWrong' m 1 = ((0.49) ^ (m-1)) * (0.51) * (choose m 1) * (0.98)
crowdWrong' m i = ((0.49) ^ (m-i)) * ((0.51) ^ i) * (choose m i) * (0.98)
                  + (crowdWrong' m (i - 1))

choose :: Integer -> Integer -> Integer
choose n 0 = 1
choose 0 k = 0
choose n k = (choose (n-1) (k-1)) * n `div` k

GHCi的输出是:

untitled.hs:5:55:
    Could not deduce (b ~ Integer)
    from the context (Fractional b, Integral b)
      bound by the type signature for
                 crowdWrong' :: (Fractional b, Integral b) => b -> b -> b
      at untitled.hs:(5,1)-(7,42)
      `b' is a rigid type variable bound by
          the type signature for
            crowdWrong' :: (Fractional b, Integral b) => b -> b -> b
          at untitled.hs:5:1
    In the first argument of `choose', namely `m'
    In the second argument of `(*)', namely `(choose m 1)'
    In the first argument of `(*)', namely
      `((0.49) ^ (m - 1)) * (0.51) * (choose m 1)'
Failed, modules loaded: none.

我不知道如何解决这个问题,我想这会更容易。

编辑:

所以现在我有了这个:

crowdWrong :: Num b => Integer -> b
crowdWrong m = crowdWrong' m m

crowdWrong' :: Num b => Integer -> Integer -> b
crowdWrong' m 1 = ((0.49) ^ (m-1)) * (0.51) * (choose m 1) * (0.98)
crowdWrong' m i = ((0.49) ^ (m-i)) * ((0.51) ^ i) * (choose m i) * (0.98)
                 + (crowdWrong' m (i - 1))

choose :: Integer -> Integer -> Integer
choose n 0 = 1
choose 0 k = 0
choose n k = (choose (n-1) (k-1)) * n `div` k
但是,GHCi仍然抱怨。

untitled.hs:5:48:
    Could not deduce (b ~ Integer)
    from the context (Num b)
      bound by the type signature for
                 crowdWrong' :: Num b => Integer -> Integer -> b
      at untitled.hs:(5,1)-(7,42)
      `b' is a rigid type variable bound by
          the type signature for
            crowdWrong' :: Num b => Integer -> Integer -> b
          at untitled.hs:5:1
    In the return type of a call of `choose'
    In the second argument of `(*)', namely `(choose m 1)'
    In the first argument of `(*)', namely
      `((0.49) ^ (m - 1)) * (0.51) * (choose m 1)'
Failed, modules loaded: none.

2 个答案:

答案 0 :(得分:7)

您的代码基本上是正确的,但您为各个部分请求的类型不匹配。

  1. choose必须接受并返回Integer s。这本身就可以,但是......

  2. crowdWrong'必须能够接收并返回 bFractional的任何类型IntegralInteger只是一种具体类型(并且不是Fractional的实例,用于启动)。这就是你得到的错误:~是Haskell如何拼写类型相等,所以“无法推断(b ~ Integer)”意味着bInteger。请注意,这与Java和其他OO语言不同;类型签名(例如crowdWrong' :: (Fractional b, Integral b) => b -> b -> b表示crowdWrong'必须能够接收并返回任何此类b,而不是某些此类{ {1}}。 (它被称为参数多态,它就像泛型/模板。)

    这个错误让你咬了两次。第一个问题是b期望choose个参数,但您已经传递了Integerm,它们是任意类型i。这里最简单的解决方法就是制作bm i s,无论如何看起来(看方程式)都是正确的。您使用Integerm的唯一其他地方是i的指数,其类型为(^)。换句话说,(^) :: (Integral b, Num a) => a -> b -> a的左侧和右侧不需要具有相同的类型。

    第二个问题是(^)会返回choose结果,但您将其乘以小数。您可以使用Integer来解决此问题,fromInteger :: Num a => Integer -> a允许您在Num中构建任何类型的Integer ber。因此,代替choose m 1,您可以编写fromInteger (choose m 1)(或者,想象一下,fromInteger (m `choose` 1);反引号允许您编写任何函数中缀)。这甚至会编译!然而...

  3. 没有FractionalIntegral类型,因此您无法调用这些功能。 Fractional类型类用于类似有理数的事物,而Integral类型类用于类似整数的事物。 (这就是为什么Fractional(/)Integralquot / div的原因。)通常情况下,如果您在类型签名中看到这些内容,那么概念类型错误。幸运的是,这很容易解决;由于mi现在是Integer s,您可以摆脱Integral约束,只有Fractional(这就是Haskell将推断的你)。

  4. 总而言之,你最终得到了新代码

    crowdWrong :: Fractional a => Integer -> a
    crowdWrong m = crowdWrong' m m
    
    crowdWrong' :: Fractional a => Integer -> Integer -> a
    crowdWrong' m 1 = (0.49 ^ (m-1)) * 0.51 * fromIntegral (m `choose` 1) * 0.98
    crowdWrong' m i = (0.49 ^ (m-i)) * (0.51 ^ i) * fromIntegral (m `choose` i) * 0.98
                      + (crowdWrong' m (i - 1))
    
    choose :: Integer -> Integer -> Integer
    choose n 0 = 1
    choose 0 k = 0
    choose n k = ((n-1) `choose` (k-1)) * n `div` k
    

    (我冒昧地删除了一些冗余的括号并切换到choose的中缀形式。)

    这似乎并不完全符合您的总和:我认为您应该crowdWrong m $ m `quot` 2i应该在0而不是1找到最低点。 crowdWrong'中的重复很烦人。您可以将代码编写为文字sum,从而避免手动递归。

    crowd :: Fractional a => Integer -> a
    crowd m = sum [ 0.49^(m-i) * 0.51^i * fromIntegral (m `choose` i) * 0.98
                  | i <- [0 .. m `quot` 2] ]
    

答案 1 :(得分:1)

您的问题是您使用的是假类型。首先,您不能同时使用bFractional类型的Integral类型,但这是b crowdWrongcrowdWord'的{​​{1}} {1}}。相反,您应该使用Num b作为上下文 您的编译器抱怨的问题是,您明确表示choose获取了两个Integer个参数,但在crowdWrong'中,您为其提供了类型为Num b => b的参数。您应该将crowdWrong'的类型签名更改为Num b => Integer -> Integer -> b,将crowdWrong的类型更改为Num b => Integer -> b