Haskell, которая принимает тип и значение и проверяет, имеет ли значение этот тип

Я пытаюсь сделать простой интерпретатор Схемы в Haskell. Как часть этого, я реализую некоторые примитивные операторы типа number?, string? и др.

У меня такой код:

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

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

И мне хотелось бы что-то вроде

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

Другими словами, я хотел бы создать эквивалент isNumber, указав "isType Number". Возможно ли это как-то? Я изо всех сил пытаюсь найти что-то подобное в Google, может быть, потому, что я не знаю, как назвать ситуацию.

Ответ 1

Я предполагаю, что у вас есть что-то вроде этого:

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

... и вам нужна функция, которая проверяет, является ли значение LispVal конкретным конструктором (String, Number, & c.) на основе некоторого аргумента.

На самом деле нет простого, общего способа сделать это, к сожалению.

Вы можете прибегнуть к строковым сравнениям:

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

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

Или вы можете сравнить типы двух LispVal s:

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

... и затем создайте фиктивное значение для сравнения с isType.

Вы также можете сделать "тип" и реализовать свое отражение на LispVal s, а затем сравнить на основе:

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

Некоторые варианты одного из этих подходов, вероятно, являются вашим лучшим вариантом. Существуют и другие способы, основанные на более продвинутых функциях Haskell, но они, вероятно, не стоят проблем, если интерпретируемые типы языков гораздо более тесно связаны с типами Haskell.