Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell function that takes a type and a value and checks if value has that type

Tags:

types

haskell

I'm trying to make a simple Scheme interpreter in Haskell. As part of this, I'm implementing some primitive operators like number?, string? etc.

I have code like this:

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

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

And what I'd like is something like

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

In other words, I'd like to create the equivalent of isNumber by saying "isType Number". Is this possible somehow? I'm struggling to find anything similar in Google, maybe because I don't know what to call the situation.

like image 288
Daniel Eliasson Avatar asked Jan 21 '12 23:01

Daniel Eliasson


1 Answers

I'm assuming you have a type something like this:

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

...and you want a function that tests whether a LispVal value is a particular constructor (String, Number, &c.) based on some argument.

There's not really a straightforward, generic way to do this, unfortunately.

You could resort to string comparisons:

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

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

Or you could compare the types of two LispVals:

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

...and then create a dummy value to compare with for isType.

You could also make a "type" value and implement a sort of reflection on LispVals, then compare based on those:

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

Some variation on one of these approaches is probably your best option. There are other ways, based on more advanced features of Haskell, but they're probably not worth the hassle unless the interpreted language's types tie much more closely to Haskell's types.

like image 149
C. A. McCann Avatar answered Oct 11 '22 23:10

C. A. McCann