1

私はこの挑戦的な言語を楽しんでおり、現在は学校の課題に取り組んでいます。

これはそれが言っていることです:私はユーザーに数字のリストを要求する必要があり、次にリストの平均を表示する必要があります。私はそれを理解することにとても近づいています。ただし、この奇妙な解析エラーが発生します。

"Exception: user error (Prelude.readIO: no parse)" 

これが私のコードです:

module Main (listM', diginums', getList, main) where 

import System.IO     
import Data.List

diginums' = []
listM' = [1, 2, 3]
average' = (sum diginums') / (fromIntegral (length diginums'))
getList :: IO [Double]
getList = readLn

main = do
      putStrLn "Please enter a few numbers" 
      diginums' <- getList
      putStrLn $ show average' 

端末プロンプト:Enter a few #'s

私が入ります :123

ERROR : Exception: user error (Prelude.readIO: no parse)

関数が平均を計算するために正しく機能していることはわかっています。今私の問題は、ユーザーから数値のリストを取得するときに、それらを正しく解析しDoubleて平均関数を入力できないことだと思います。

4

2 に答える 2

3

あなたの型署名はそれを言います

getList :: IO [Double]
getList = readLn

s のリストを読み取りますDouble。つまり、フォームの入力を期待します

[123, 456.789, 1011.12e13]

しかし、単一の数値として読み取れるものを指定しました"123"。したがって、read失敗し、入力を として解析できませんでした[Double]

構文的に正しい Haskell 値ではなく、別の形式で入力を解析したい場合 (スペースで区切られた数字のリストなど)、 を使用することはできませんがreadLn、目的の形式のパーサーを自分で作成する必要があります。上記のスペースで区切られた数字のリストについては、非常に簡単です。

getList :: IO [Double]
getList = do
    input <- getLine
    let nums = words input
    return $ map read nums

空行で終わるそれぞれの行の数値の形式でリストを取得する場合は、アキュムレータを使用して再帰を使用します。

getList :: IO [Double]
getList = completeList []

completeList :: [Double] -> IO [Double]
completeList acc = do
    line <- getLine
    if null line
        then return (reverse acc)
        else completeList (read line : acc)

より複雑な形式または厳密でない形式のパーサーは、作成が難しくなります。

解析が修正されると、値が不変であるという事実にまだ慣れていないという問題に遭遇します。

diginums' = []
listM' = [1, 2, 3]
average' = (sum diginums') / (fromIntegral (length diginums'))

は 3 つの値Doubleaverage'定義します。値は空のリストに関して定義されますdiginums'。したがって、その値は

sum diginums' / fromIntegral (length diginums') = 0 / 0

ですNaN

必要なのは、 のリストの平均を計算し、Doubleそれを に入力されたリストに適用する関数ですmain

average :: [Double] -> Double
average xs = sum xs / fromIntegral (length xs)

main = do
    putStrLn "Please enter a few numbers" 
    numbers <- getList
    print $ average numbers
于 2012-07-12T23:35:42.680 に答える
3

Haskell には変更可能な変数はありませんがdiginums'、空のリストとして初期化してからgetList.

average'代わりに、次のように、数値のリストを引数として渡したい場合があります。

module Main (getList, main) where

import System.IO
import Data.List


average' ds = (sum ds) / (fromIntegral (length ds))
getList :: IO [Double]
getList = readLn

main = do
      putStrLn "Please enter a few numbers"
      diginums' <- getList
      putStrLn $ show $ average' diginums'

また、ダニエルが言ったように、コード化した方法を考えると、Haskell リテラル リスト構文を使用して入力する必要があります。

于 2012-07-13T00:02:35.563 に答える