2011-06-23 17 views
5

Próbuję napisać sobie schemat w 48-godzinnym samouczku i jako ktoś nowy w haskell jest to dość trudne. Obecnie pracuję nad problemem, w którym mam dodać możliwość analizowania wektorów schematycznych (sekcja 3.4 ćwiczenie 2).Parsowanie wektorów schematu w haskell przy użyciu tablic

używam tego typu danych:

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

do analizowania, szukam „# (” następnie próbuje zanalizować zawartość wektorowej, upuść je na liście i przekonwertować ten wykaz array:

Próbuję użyć funkcji parsowania list, którą już posiadam i używam, ale analizuje listy schematów na liście LispVal powyżej i mam problem z przywróceniem jej do zwykłej listy. przynajmniej tak uważam mój problem:

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 

a oto lista parser:

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

Wszelkie pomysły jak to naprawić? Dzięki, Simon

-edit- Oto błąd kompilacji otrzymuję:

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

Czy dostajesz żadnej informacji o błędzie podczas kompilacji kodu? Myślę, że definicja 'parseVectorInternals' ma błąd typu, ale nie jestem pewien, czy jest to jedyny błąd w kodzie, czy nie. Również wcięcie definicji "parseVector" jest dziwne. –

+0

Edytowałem oryginalne pytanie w celu uwzględnienia błędu - wcięcie parsevector jest problemem renderowania, w samym kodzie jest w porządku. – SimonBolivar

Odpowiedz

6

Nie zapewniają lispValtoList ale przypuszczam, że masz następujące rodzaje

lispValtoList :: LispVal -> [LispVal] 

Byłoby sugeruje kompilatorowi, aby sądzić, że parseList jest typu a -> LispVal. Ale tak nie jest, ponieważ jest to Parser LispVal, a więc coś w rodzaju P String -> [(LispVal,String)].

Musisz wyodrębnić wartość LispVal, która została przeanalizowana przed umieszczeniem jej na liście. Więc parseVectorInternals musi prawdopodobnie wyglądać

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

Można napisać coś bardziej zwarta, ale kod ten stara się być self-dokumentowane;)

+0

Fraikin - Ups, już tam jest. Sądzę, że to, co próbowałem zrobić, to dokładnie to, co mówisz, że powinienem zrobić. Intencją lispValToList jest pobranie listy z listy 'LispVal List'. Czy mówisz, że używam operatora (.) Niepoprawnie? – SimonBolivar

+1

@ SimonBolivar W tym przypadku operator (.) Jest niepoprawny, ponieważ zwracana wartość 'parseList' nie jest zgodna z argumentem' lispValToList'. 'parseList' zwraca monadę, która jest czymś w rodzaju pudełka z wartością. '<-' wewnątrz bloku' do' pobiera wartość z pudełka, następnie możesz przekazać wartość do 'lispValToList'. (http://learnyouahaskell.com/ ma lepsze wytłumaczenie monad) – Alex

+1

@ SimonBolivar Dokładnie ... problem pochodzi od operatora kompozycji. Aby go skomponować, musisz podnieść 'lispValtoList' (spójrz na' Control.Monad', jeśli nie wiesz, co to jest podnoszenie). Wygląda na to, że John F. Miller daje możliwość korekty. –

2

parseList jest Monada typu parser LispVal natomiast lispValtoList chce zwykły LispVal tak :

parseVectorInternals = listToArray . lispValtoList `liftM` parseList 

Jeśli jesteś gdzie miałem 8 tygodni temu czytanie tej samej książki co następuje pomoże także:

Wszystkie te linie są równoważne:

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

Dzięki. To pomaga, chociaż wydaje mi się, że z twoim rozwiązaniem może być kilka problemów. Po pierwsze, 'parseVectorInternals' jest typu' Parser (Array Int LispVal) ', więc potrzebuję' return' lub odpowiednika (innego 'liftM'?), Aby przywrócić go z powrotem do poprawnej monady. Po drugie, pierwsze rozwiązanie kodu daje błąd: _ Błąd analizy składniowej nie może mieszać "." [infixr 9] i "liftM" [infixl 9] w tym samym języku infix expression_ Nie jestem pewien, co zrobić z tym. Ale wersja z blokiem 'do' działa, jeśli poprzedzam ostatnią linię przez' return $ ' – SimonBolivar

Powiązane problemy