2017-01-08 20 views
0

私は実験中に取り込まれたデータを取り込める小さなプログラムを作成しようとしていますが、大部分はデータを再帰的に取り込む方法を考え出したと思いますユーザーの信号がなくなるまで、データの終了時にhaskellはException: <<loop>>を投げ、私は本当に理由を理解できません。ここでは、コードです:私の知る限りHaskell:例外<<loop>>再帰的なデータ入力の場合

readData :: (Num a, Read a) => [Point a] -> IO [Point a] 
readData l = do putStr "Enter Point (x,y,<e>) or (d)one: " 
       entered <- getLine 
       if (entered == "d" || entered == "done") 
        then return l 
        else do let l = addPoint l entered 
          nl <- readData l 
          return nl 

addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a] 
addPoint l s = l ++ [Point (dataList !! 0) (dataList !! 1) (dataList !! 2)] 
    where dataList = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a] 

checkInputData :: [String] -> [String] 
checkInputData xs 
    | length xs < 2 = ["0","0","0"] 
    | length xs < 3 = (xs ++ ["0"]) 
    | length xs == 3 = xs 
    | length xs > 3 = ["0","0","0"] 

、例外は、無限ループがどこかに存在していることを示しているが、私はこれが発生している理由を把握することはできません。私が知る限り、 "完了"が入力されると、現在のレベルは、リストのlを返すだけで、関数の以前の反復をカスケードする必要があります。

ありがとうございました。 (私はそれを行う方法を見つけ出す一度はい、checkInputDataは、適切なエラー処理を持っています。)

答えて

4

<<loop>>は、基本的には、GHCが自分自身(参照this question、またはthis oneのためにすぐに依存する値によって引き起こされる無限ループを検出したことを意味しますさらに興味深い場合は技術的な詳細)。トリガーされる。この場合、:

else do let l = addPoint l entered 

あなたは、引数として渡されたlをシャドウこの定義を、自身の面でlを定義します。あなたは...のように、元のlの面で新しい価値、l'を、定義

else do let l' = addPoint l entered 

を...何かを書くことを意味しました。 hightlightedとして、

<interactive>:171:33: warning: [-Wname-shadowing] 
    This binding for ‘l’ shadows the existing binding 
     bound at <interactive>:167:10 

また:

カールが指摘するように、-WallをオンにGHCになるだろう(コマンドラインでGHCに渡すことで、たとえば、またはGHCiの中:set -Wallとは)シャドーイングについて警告しますそれは、この場合には、無関係な提案として

readData (addPoint l entered) 

:dfeuerにより、elseブランチ全体doブロックを置き換えることができlength(!!)のパターンをパターンマッチングで置き換えることをお勧めします。例えば、checkInputDataは次のように記述することができます。

checkInputData :: [String] -> [String] 
checkInputData xs = case xs of 
    [_,_] -> xs ++ ["0"] 
    [_,_,_] -> xs 
    _ -> ["0","0","0"] 

addPoint、その順番に、なる可能性があります:あなたがそうcheckInputDataを変更した場合、それはどのだろう、(String, String, String)トリプル返すことも、すっきりとなり

addPoint :: (Num a, Read a) => [Point a] -> String -> [Point a] 
addPoint l s = l ++ [Point x y z] 
    where [x,y,z] = (map read $ checkInputData . splitOn "," $ s) :: (Read a) => [a] 

あなたが正確に3つの値を読み込んでいることをよりよく表現してください。

+1

'-Wall'フラグを追加するとシャドーイングが指摘され、何が間違っていたのかを強く示唆していることに気付くでしょう。 – Carl

+1

実際、 'let'は周囲の' do'と一緒に冗長です。必要なのは 'else readData(addPoint l entered)'だけです。 – dfeuer

関連する問題