2011-06-23 27 views
5

我在48小時的教程中嘗試編寫自己的方案,並且作爲haskell的新成員,這非常困難。 我目前正在研究一個問題,我應該添加解析方案向量的能力(3.4節練習2)。在使用數組的haskell中解析方案向量

我使用這個數據類型:

data LispVal = Atom String     
     | List [LispVal]     
     | Vector (Array Int LispVal) 

要解析,我在尋找「#(」然後試圖解析向量內容,在列表中把它們和列表轉換成array。

我想使用列表解析功能,我已經有了,但它解析方案列表到上面的LispVal列表,我很難讓它回到常規列表中。至少這就是我認爲我的問題是。

lispValtoList :: LispVal -> [LispVal] 
lispValtoList (List [a]) = [a] 

parseVector :: Parser LispVal 
parseVector = do string "#(" 
      vecArray <- parseVectorInternals  
      char ')' 
      return $ Vector vecArray 

parseVectorInternals :: Parser (Array Int LispVal) 
parseVectorInternals = listToArray . lispValtoList . parseList 

listToArray :: [a] -> Array Int a 
listToArray xs = listArray (0,l-1) xs 
    where l = length xs 

和這裏的列表解析器:

parseList :: Parser LispVal 
parseList = liftM List $ sepBy parseExpr spaces 

關於如何解決此問題的任何想法? 謝謝, 西蒙

CNC中 這裏的編譯錯誤,我得到:

Couldn't match expected type a -> LispVal' against inferred type Parser LispVal' In the second argument of (.)' namely parseList' In the second argument of (.)' namely lispValToList . parseList' In the expression: listToArray . lispValToList . parseList

+0

你得到任何錯誤消息,當您編譯代碼?我認爲'parseVectorInternals'的定義有一個類型錯誤,但我不確定它是否是代碼中唯一的錯誤。另外,'parseVector'定義的縮進很奇怪。 –

+0

我編輯了原始問題以包含錯誤 - parseVector indenting是一個呈現問題,在實際代碼中很好。 – SimonBolivar

回答

6

你不提供lispValtoList但我想它有以下類型

lispValtoList :: LispVal -> [LispVal] 

這建議編譯器認爲parseLista -> LispVal類型。但它不是因爲它是Parser LispVal,所以類似P String -> [(LispVal,String)]

您必須先提取已解析的LispVal值,然後再將其放入列表中。 所以parseVectorInternals必須看起來可能像

parseVectorInternals = do parsedList <- parseList 
          let listOfLispVal = lispValtoList parsedList 
          return $ listToArray listOfLispVal 

你可以寫的東西更緊湊,但是這個代碼試圖自行記錄;)

+0

Fraikin - 哎呀,它現在在那裏。我想我想要做的就是你說我應該做的事。 lispValToList的意圖是將haskell列表從「LispVal列表」中取出。您是否說我錯誤地使用了(。)運算符? – SimonBolivar

+1

@SimonBolivar在這種情況下,(。)運算符不正確,因爲'parseList'的返回值與'lispValToList'的參數不匹配。 'parseList'返回一個monad,它就像一個保存一個值的盒子。 'do'塊內的'<-'將該值從框中取出,然後您可以將該值傳遞給'lispValToList'。 (http://learnyouahaskell.com/對單子有更好的解釋) – Alex

+1

@SimonBolivar確切地說......問題來自組合運算符。你需要解除'lispValtoList'來組成他(如果你不知道提升是什麼的話,請查看'Control.Monad')。 John F. Miller似乎給出了可能的更正。 –

2

parseListparser LispVal類型的單子,而lispValtoList想要一個普通的LispVal所以:

parseVectorInternals = listToArray . lispValtoList `liftM` parseList 

如果你是在那裏我是18周前閱讀同一本書,下面將幫助您以及:

所有這些都是等同的:

parseVectorInternals = (listToArray . lispValtoList) `liftM` parseList 
parseVectorInternals = liftM (listToArray . lispValtoList) parseList 
parseVectorInternals = parseList >>= \listLispVal -> return listToArray (lispValtoList listLispVal) 
parseVectorInternals = do 
    listLispVal <- parseList 
    return listToArray (lispValtoList listLispVal) 
+1

謝謝。儘管我認爲解決方案可能存在一些問題,但這有助於解決問題。首先,'parseVectorInternals'的類型是'Parser(Array Int LispVal)',所以我需要一個'return'或者等價的(另一個'liftM'?)來將它恢復到正確的monad中。其次,第一個代碼解決方案給出錯誤:_Precedence解析錯誤不能混合'。' [infixr 9]和'liftM'[infixl 9]在同一個中綴表達式中我不知道該怎麼做。但是,如果我用'return $'作爲最後一行的前綴,那麼帶'do'塊的版本將起作用 – SimonBolivar