2012-01-04 34 views
6

我正在解析一個CSV文件到CSV類型,這是一個列表的記錄,這是一個字段,這只是字符串的列表。插入一個新行然後嘗試訪問csv後,我得到c堆棧溢出錯誤。我讀過這個錯誤可能來自使用尾遞歸過大的「thunk」,但我不認爲這是我做錯了什麼?Haskell使用擁抱「錯誤 - C堆棧溢出」

type CSV = [Record] 
type Record = [Field] 
type Field = String 

run :: IO() 
run = 
do 
    inFile <- readFile "myFile.csv" 
    let csv = parse inFile 
    let csv = (insertRow "abc,def,ghi" csv) 
    putStr (show csv) 

insertRow :: String -> CSV -> CSV 
insertRow newRow csv = csv ++ [toRecord newRow] 

parse :: String -> CSV 
parse file = map toRecord (parseLines file "" []) 

toRecord :: String -> Record 
toRecord line = parseWords line "" [] 

-- parseLine input partialCSV records 
parseLines :: String -> String -> [String] -> [String] 
parseLines [] partial records = records ++ [partial] 
parseLines ('\r':xs) partial records = parseLines xs [] (records ++ [partial]) 
parseLines (x:xs) partial records = parseLines xs (partial ++ [x]) records 

-- parseWords input partialRecord fields 
parseWords :: String -> String -> [String] -> [String] 
parseWords [] partial fields = fields ++ [partial] 
parseWords ('"':xs) partial fields = parseQuotes xs partial fields 
parseWords (',':xs) partial fields = parseWords xs [] (fields ++ [partial]) 
parseWords (x:xs) partial fields = parseWords xs (partial ++ [x]) fields 

parseQuotes :: String -> String -> [String] -> [String] 
parseQuotes ('"':xs) partial fields = parseWords xs [] (fields ++ [partial]) 
parseQuotes (x:xs) partial fields = parseQuotes xs (partial ++ [x]) fields 
+5

與您的問題無關,擁抱的最後一個版本已超過五年。語言進一步發展,ghci也表現更好(並帶有編譯器;)。雖然很傷心,但我建議不要再使用擁抱(直到有人復活)。 – 2012-01-04 14:36:45

回答

2

let csv = ...看起來很可疑。你可以嘗試解開這兩個變量嗎?它可能不會做你想要的(在Haskell let是遞歸的)。

+0

感謝您的快速回復,我將兩條線合併到一條線上,並且工作正常! – user1130083 2012-01-04 14:52:44

5

let綁定是遞歸的,所以這行

let csv = (insertRow "abc,def,ghi" csv) 

創建一個無限循環,你本身來在不終止的方式定義csv。將其更改爲

let csv' = ... 

並在下一行中打印csv'

+0

感謝您的快速和有益的答覆!雖然我不完全確定讓。這是否意味着我無法更改csv,我必須繼續使用csv',csv''...? – user1130083 2012-01-04 14:53:46

+2

在Haskell中,所有值都是不可變的,因此無論如何您都無法更改csv。所以一般來說,您必須爲您獲得的值作爲「修改」的結果賦予新名稱。但是,您可以通過_shadowing_名稱來重複使用名稱,但只有在陰影/回彈名稱未出現在綁定的RHS上時才起作用,否則RHS上的出現將引用新名稱循環。你可以有'do {blah;讓{x = foo; };讓{y = bar x; };讓{x = baz y; }; quux x; }'和'x'的第二個綁定會影響第一個。但不是(通常)'讓x = foo x',這個循環。 – 2012-01-04 15:03:31

+2

這樣的陰影非常令人沮喪。所以......假裝你不能這樣做,只需在嵌套的let中使用唯一的名字(在合理的情況下)。 – 2012-01-04 18:36:06