2011-06-23 54 views
5

Tôi đang cố gắng viết cho mình một sơ đồ trong 48 giờ hướng dẫn và như một người mới để haskell nó khá khó khăn. Tôi hiện đang làm việc về một vấn đề mà tôi phải thêm khả năng phân tích cú pháp lược đồ (phần 3.4 bài tập 2).Phân tích các vectơ lược đồ trong haskell sử dụng các mảng

Tôi đang sử dụng kiểu dữ liệu này:

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

Để phân tích, tôi đang tìm '# (' sau đó cố gắng để phân tích các nội dung vector, thả chúng vào trong một danh sách và chuyển đổi danh sách đó để một Tôi đang cố gắng sử dụng một chức năng phân tích danh sách mà tôi đã có và đang sử dụng nhưng nó phân tích danh sách lược đồ vào Danh sách LispVal ở trên và tôi đang gặp khó khăn trong việc đưa nó trở lại danh sách thông thường. ít nhất đó là những gì tôi nghĩ rằng vấn đề của tôi là.

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 

và đây là phân tích cú pháp danh:

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

Bất kỳ ý tưởng về làm thế nào để sửa lỗi này? Cảm ơn, Simon

-edit- Đây là lỗi biên dịch tôi nhận được:

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

Bạn có nhận được thông báo lỗi nào khi biên dịch mã không? Tôi nghĩ rằng định nghĩa của 'parseVectorInternals' có lỗi kiểu, nhưng tôi không chắc đó có phải là lỗi duy nhất trong mã hay không. Ngoài ra, sự thụt đầu của định nghĩa của 'parseVector' là lạ. –

+0

Tôi đã chỉnh sửa câu hỏi ban đầu để bao gồm lỗi - sự phân tích cú pháp parseVector là một vấn đề hiển thị, điều này là tốt trong mã thực tế. – SimonBolivar

Trả lời

6

Bạn không cung cấp lispValtoList nhưng tôi nghĩ rằng nó có các loại sau đây

lispValtoList :: LispVal -> [LispVal] 

sẽ này đề nghị trình biên dịch nghĩ rằng parseList thuộc loại a -> LispVal. Nhưng nó không phải là vì nó là Parser LispVal và vì vậy một cái gì đó như P String -> [(LispVal,String)].

Bạn phải trích xuất giá trị LispVal được phân tích cú pháp trước khi đặt nó vào danh sách. Vì vậy parseVectorInternals lẽ phải trông giống như

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

Bạn có thể viết một cái gì đó nhỏ gọn hơn, nhưng mã này cố gắng để được tự ghi;)

+0

Fraikin - Rất tiếc, giờ đã có. Tôi đoán những gì tôi đã cố gắng làm là chính xác những gì bạn đang nói tôi nên làm. Mục đích của lispValToList là lấy danh sách haskell trong danh sách 'LispVal'. Bạn đang nói rằng tôi đang sử dụng toán tử (.) Không chính xác? – SimonBolivar

+1

@SimonBolivar Trong trường hợp này, toán tử (.) Không chính xác vì giá trị trả về của 'parseList' không khớp với đối số của' lispValToList'. 'parseList' trả về một đơn nguyên, giống như một hộp chứa một giá trị. '<-' bên trong khối' do' lấy giá trị ra khỏi hộp, sau đó bạn có thể truyền giá trị cho 'lispValToList'. (http://learnyouahaskell.com/ có giải thích tốt hơn về monads) – Alex

+1

@SimonBolivar Chính xác ... vấn đề xuất phát từ toán tử thành phần. Bạn cần phải nâng 'lispValtoList' để soạn anh ta (nhìn vào' Control.Monad' nếu bạn không biết nâng là gì). Dường như John F. Miller cho phép điều chỉnh khả năng. –

2

parseList là một đơn nguyên của loại parser LispVal trong khi lispValtoList muốn một LispVal đồng bằng nên :

parseVectorInternals = listToArray . lispValtoList `liftM` parseList 

Nếu bạn đang ở đâu tôi đã 8 tuần trước đọc cùng một cuốn sách sau đây sẽ giúp bạn cũng như:

Tất cả các dòng này tương đương nhau:

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

Cảm ơn. Điều đó giúp mặc dù tôi nghĩ rằng có thể có một vài vấn đề với giải pháp của bạn. Đầu tiên, 'parseVectorInternals' là kiểu' Parser (Array Int LispVal) 'vì vậy tôi cần' return' hoặc tương đương (một 'liftM'?) Khác để lấy nó trở lại đúng monad. Thứ hai, giải pháp mã đầu tiên đưa ra lỗi: Lỗi phân tích cú pháp _Precedence không thể kết hợp '.' [infixr 9] và 'liftM' [infixl 9] trong cùng biểu thức infix Tôi không biết phải làm gì với cái đó. Nhưng, phiên bản với khối 'do' hoạt động nếu tôi mở đầu dòng cuối cùng với' return $ ' – SimonBolivar

Các vấn đề liên quan