2

ユーザーが数値を入力し続け、負の数値を入力すると平均を出力するプログラムを作成しようとしてい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.
4

1 に答える 1

6

修正方法を検討する前に、コードの何が問題なのかを見てみましょう。

機能getFloatは問題なく、あなたが思っていることを正確に実行します。

関数は、あなたが思っていることをしませhelpそのままでは、値が与えられるxとタプル(x,1.0)ifx > 0を返すだけで、それ以外の場合は . を返します(0.0,0.0)。タイプを与えることができます:

help :: Double -> (Double,Double)

一方、あなたはそれがタイプを持つことを意図していると思います

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

意図したバージョンを次のように記述できます。

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

関数には、次のように括弧で囲まれaverageた式があります。これがエラー メッセージの理由です: you can only apply to something of type but you'll tr​​y to apply it to something of type , so the error is throw.fst help x(fst help) xfst(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)

これは一般的な原則を示しています。使用する値の入力と出力には純粋なコードを使用し、それらの値の変換には純粋なコードを使用します。

于 2013-03-06T22:25:29.297 に答える