Haskell IO平均功能IO,纯粹vs不尝试尝试

时间:2013-03-06 22:04:42

标签: haskell io functional-programming

我正在尝试编写一个用户输入数字的程序,并在输入负数后输出平均值 这是我保留pure separate from unpure的尝试 有人可以给我提供修复此代码的提示,以及纯粹和不可靠的分离提示。

getFloat :: IO Float
getFloat = do line <- getLine
              return (read line:: Float)  

“不纯洁的部分”

average :: IO Float
average = do x <- getFloat
             return((fst help x)/(snd help x))

“纯粹的一部分”

help x 
    |x>=0 = (x+sum1, 1+ counter)
    |otherwise = (sum1 , counter)
    where 
    sum1 = 0.0
    counter = 0.0

我收到此错误

.hs:45:26:
    Couldn't match expected type `(t0 -> Float, b0)'
                with actual type `t1 -> (t1, t2)'
    In the first argument of `fst', namely `help'
    In the first argument of `(/)', namely `(fst help x)'
    In the first argument of `return', namely
      `((fst help x) / (snd help x))'
Failed, modules loaded: none.

1 个答案:

答案 0 :(得分:6)

在查看如何修复代码之前,先看看代码有什么问题。

函数getFloat很好,并且完全符合您的想法。

函数help 执行您认为的操作。实际上,当输入值x时,它只返回元组(x,1.0) if x > 0,否则返回(0.0,0.0) ..你可以给它类型:

help :: Double -> (Double,Double)

而我猜你打算让它有类型

help :: [Double] -> (Double,Double)

你可以像这样编写你想要的版本:

help xs = (sum xs, fromIntegral (length xs))

在函数average中,您有表达式fst help x,其括号如下:(fst help) x。这就是出现错误消息的原因:您只能将fst应用于(a,b)类型的某些内容,但您尝试将其应用于Double -> (Double,Double)类型的内容,因此会引发错误。

如果我要写这个函数,我可能会做这样的事情:

import Data.List (takeWhile) -- take elements from a list while predicate is satisfied

avg xs = sum xs / fromIntegral (length xs)

main = do numbers <- fmap (takeWhile (>0) . map read . words) getContents
          return (avg numbers)

函数avg是纯粹的。函数takeWhile (>0) . map read . words也是纯粹的,可以这样考虑:

helper :: String -> [Double]
helper = takeWhile (>0) . map read . words

main = do numbers <- fmap helper getContents
          return (avg numbers)

这说明了一般原则 - 使用不纯的代码输入和输出您将要使用的值,并使用纯代码转换这些值。