2012-03-10 55 views
3

我写了一个函数,(应该)采取布尔的无限列表和计算时真亦假值在第一n个元素的比例:型铸造在Haskell,分数和Int

prob n list = foldr (+) 0 (map boolToInt (take n list))/n 
    where boolToInt b 
     | b == True = 1 
     | otherwise = 0 

不幸这不是工作:

No instance for (Fractional Int) 
    arising from a use of `/' 
Possible fix: add an instance declaration for (Fractional Int) 
In the expression: foldr (+) 0 (map boolToInt (take n list))/n 
In an equation for `prob': 
    prob n list 
     = foldr (+) 0 (map boolToInt (take n list))/n 
     where 
      boolToInt b 
      | b == True = 1 
      | otherwise = 0 
Failed, modules loaded: none. 

我试图做一个转换,但不工作之一:

prob n list = foldr (+) 0 (map boolToInt (take (fromIntegral (toInteger n)) list))/n 
    where boolToInt b 
     | b == True = 1 
     | otherwise = 0 

它的编制,但只要我尝试调用的函数,我得到一个错误:

*Main> prob 50 toCoin1 
<interactive>:1:6: 
Ambiguous type variable `a0' in the constraints: 
    (Num a0) arising from the literal `50' at <interactive>:1:6-7 
    (Integral a0) arising from a use of `prob' at <interactive>:1:1-4 
    (Fractional a0) arising from a use of `prob' at <interactive>:1:1-4 
Probable fix: add a type signature that fixes these type variable(s) 
In the first argument of `prob', namely `50' 
In the expression: prob 50 toCoin1 
In an equation for `it': it = prob 50 toCoin1 

有什么建议?

回答

11

您正在转换错误的地方。尝试在整个foldrn附近附上fromRational

prob n list = fromIntegral count/fromIntegral n 
    where count = foldr (+) 0 (map boolToInt (take n list)) 
      boolToInt b 
      | b == True = 1 
      | otherwise = 0 

哦,你boolToInt功能是相同的fromEnum专门到Bool秒。

prob n list = fromIntegral count/fromIntegral n 
    where count = foldr (+) 0 (map fromEnum (take n list)) 

与你试图做什么的根本问题是你强加给第一个参数prob相互冲突的要求。您使用toInteger约束nIntegral,但其在/中的使用要求它是Fractional,并且没有类型是IntegralFractional

+0

这不适合我,应'fromRational'是'fromIntegral'? – huon 2012-03-10 02:57:19

+0

@dbaupp:呃,是的,它应该。猜猜我不应该在网络浏览器中编码。 – 2012-03-10 03:03:06

+0

@dbaupp:如果您为'prob'编写顶级类型声明,例如'prob :: Int - > [Bool] - > Float',那么你会得到一个更好的错误信息。 – 2012-03-10 03:05:06

0

BoolEnum的一个实例,所以boolToInt已由fromEnum提供。此外,foldrsum,因此整个功能可以简化为:

prob n list = (fromIntegral . sum . map fromEnum . take n) list/fromIntegral n 

我们能抽象出用于计算平均值(尽管这将需要确定列表的长度的代码,我们已经知道):

mean xs = (fromIntegral . sum) xs/(fromIntegral . length) xs 

prob n = mean . map fromEnum . take n 
+0

平均函数是一个不好的消费者:它在两个点使用xs,所以它将保留xs的头部,直到总和达到最后一个元素。整个列表必须在内存中......通常的回应是在一次遍历中累加和和长度:'foldl'(\(!sum,!len)x - >(sum + x,len + 1))(0,0)'。 – Jedai 2012-03-10 14:13:48

+0

不错!优化器无法为你做到这一点太糟糕了...... – pat 2012-03-10 17:06:20

+0

很难发现这种情况,并且确定正确的方法来做到这一点(有懒惰的担忧也要考虑,你不会希望为所有操作员完成此操作...)。另一方面,如果你开始编写并行代码,即使最初的平均值并行化也可能是一个好消费者(因为两个遍历都可以同时发生)。 – Jedai 2012-03-10 17:54:53