2012-01-21 28 views
10

Tôi đang cố gắng tạo một trình thông dịch Scheme đơn giản trong Haskell. Là một phần của điều này, tôi đang thực hiện một số toán tử nguyên thủy như số ?, chuỗi? vvChức năng Haskell lấy một loại và một giá trị và kiểm tra nếu giá trị có loại

tôi có mã như thế này:

isNumber :: [LispVal] -> LispVal 
isNumber ([Number n]) = Bool True 
isNumber   _ = Bool False 

isString :: [LispVal] -> LispVal 
isString ([String n]) = Bool True 
isString   _ = Bool False 

Và những gì tôi muốn là một cái gì đó giống như

isType :: ?? -> [LispVal] -> LispVal 
isType (typeName [typeName n]) = Bool True 
isType      _ = Bool False 

Nói cách khác, tôi muốn tạo tương đương với ISNUMBER bởi nói "isType Number". Điều này có thể bằng cách nào đó? Tôi đang đấu tranh để tìm thấy bất cứ điều gì tương tự trong Google, có thể bởi vì tôi không biết những gì để gọi tình hình.

+4

Bạn có lẽ nên nói "hàm tạo" thay vì "loại", vì nó được viết, câu hỏi này thậm chí không thực sự có ý nghĩa trong ngữ cảnh của Haskell. Bạn đang đại diện cho các kiểu Lisp với các hàm tạo Haskell, nhưng điều đó không liên quan trực tiếp đến câu hỏi Haskell mà nó dẫn đến. – ehird

+0

Data.Typeable có thể đáng xem, nhưng nó không xuất hiện mà bạn cần kiểm tra động tại đây. – ExternalReality

+1

Xem tại đây cho [giải pháp mẫu Haskell] (http://stackoverflow.com/questions/7213974/how-to-examine-a-quoted-data-constructor-name-in-template-haskell/7214422#7214422). Với điều này bạn có thể làm 'isNumber = $ (isA 'Number)' – hammar

Trả lời

8

Tôi giả sử bạn có một loại một cái gì đó như thế này:

data LispVal = String String | Number Double -- &c.... 

... và bạn muốn có một hàm kiểm tra xem một giá trị LispVal là một nhà xây dựng đặc biệt (String, Number, & c.) dựa trên một số đối số.

Không thực sự là một cách đơn giản, chung chung để làm điều này, thật không may.

Bạn có thể nghỉ mát để so sánh chuỗi:

getTypeName :: LispVal -> String 
getTypeName (String _) = "String" 
getTypeName (Number _) = "Number" 

isType :: String -> [LispVal] -> LispVal 
isType name [val] = Bool (name == getTypeName val) 
isType _ _ = Bool False 

Hoặc bạn có thể so sánh các loại hai LispVal s:

sameType :: LispVal -> LispVal -> LispVal 
sameType (String _) (String _) = Bool True 
sameType (Number _) (Number _) = Bool True 
sameType _ _ = Bool False 

... và sau đó tạo ra một giá trị giả để so sánh với cho isType .

Bạn cũng có thể tạo ra một "loại" giá trị và thực hiện một loại phản ánh trên LispVal s, sau đó so sánh dựa trên những:

data LispType = LispString | LispNumber | LispType 

getType :: LispVal -> LispVal 
getType (String _) = Type LispString 
getType (Number _) = Type LispNumber 
getType (Type _) = Type LispType 

isType :: LispVal -> [LispVal] -> LsipVal 
isType t [v] = isEqual t (getType v) 
isType _ _ = Bool False 

Một số biến thể của một trong những phương pháp có lẽ là lựa chọn tốt nhất của bạn. Có nhiều cách khác, dựa trên các tính năng nâng cao hơn của Haskell, nhưng chúng có lẽ không đáng để giải quyết rắc rối trừ khi các kiểu ngôn ngữ diễn giải được gắn chặt chẽ hơn với các kiểu của Haskell.

+0

Sử dụng cú pháp mẫu 'C {}' có thể là một ý tưởng hay cho 'getType' để giảm bớt bản mẫu. (Giống như 'getTypeName' và' sameType'.) – ehird

+2

'getType (Type _) = Kiểu LispType' ... kiểu của kiểu là kiểu kiểu? o_O? –

+0

Cảm ơn bạn đã trả lời tuyệt vời! Tôi nghĩ tùy chọn thứ hai sẽ dễ dàng nhất hiện nay. Nó vẫn cần một chút mô hình rõ ràng hơn so với tôi đã hy vọng, nhưng nó sẽ tiết kiệm cho tôi một vài dòng ít nhất. –

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