1

我想实现这个总和。我遇到了关于类型签名的问题。

图片

这就是它在 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.
4

2 回答 2

7

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

  1. choose必须取并返回Integers。这本身没问题,但是……</p>

  2. crowdWrong'必须能够接受和返回既是 a又是a 的任何类型。 只是一种具体类型(并且不是 , 的实例)。这就是你得到的错误:这是 Haskell 如何拼写类型相等,所以“无法推断”意味着≠ 。请注意,这与 Java 和其他 OO 语言不同;一个类型签名,例如意味着必须能够接受和返回任何这样的,而不是一些这样的。(它被称为参数多态性,它就像泛型/模板。)bFractionalIntegralIntegerFractional~(b ~ Integer)bIntegercrowdWrong' :: (Fractional b, Integral b) => b -> b -> bcrowdWrong'bb

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

    第二个问题是choose返回一个Integer结果,但是你将它乘以小数。您可以通过使用来解决此问题fromInteger :: Num a => Integer -> a,它允许您NumInteger. choose m 1因此,您可以编写fromInteger (choose m 1)(或者,花哨fromInteger (m `choose` 1)的是,;反引号允许您编写任何函数中缀)来代替。这甚至会编译!不过……</p>

  3. 没有既是Fractionaland的类型Integral,所以你不能调用这些函数。类型类用于类似Fractional有理数的事物,而Integral类型类用于类似整数的事物。(这就是为什么Fractionalhas(/)Integralhas quot/的原因div。)通常,如果您在类型签名中看到这些组合,您就会遇到概念类型错误。幸运的是,这很容易解决;因为mand iare now Integers,你可以摆脱Integral约束而只拥有Fractional(这就是 Haskell 将为你推断的)。

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

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` 2,并且i应该在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] ]
于 2013-07-03T20:06:16.177 回答
1

您的问题是您使用的是错误类型。首先,您不能同时拥有 a 和 a 的类型bFractional但这Integral就是您想要bcrowdWrongcrowdWord'成为的。相反,您应该Num b用作上下文。
你的编译器抱怨的问题是,你明确地说choose得到两个Integer参数,但是crowdWrong'你给它一个 type 的参数Num b => b。您应该更改to的类型签名和crowdWrong'toNum b => Integer -> Integer -> b的类型。crowdWrongNum b => Integer -> b

于 2013-07-03T19:42:33.420 回答