naber2
naber2

Reputation: 49

Haskell type checking in code

Could you please show me how can I check if type of func is Tree or not, in code not in command page?

data Tree = Leaf Float | Gate [Char] Tree Tree deriving (Show, Eq, Ord)
func a = Leaf a

Upvotes: 0

Views: 2545

Answers (2)

Lazersmoke
Lazersmoke

Reputation: 1741

Here's how to determine what the type of a binding is in Haskell: take something like f a1 a2 a3 ... an = someExpression and turn it into f = \a1 -> \a2 -> \a3 -> ... \an -> someExpression. Then find the type of the expression on the right hand side.

To find the type of an expression, simply add a SomeType -> for each lambda, where SomeType is whatever the appropriate type of the bound variable is. Then use the known types in the remaining (lambda-less) expression to find its actual type.

For your example: func a = Leaf a turns into func = \a -> Leaf a. Now to find the type of \a -> Leaf a, we add a SomeType -> for the lambda, where SomeType is Float in this case. (because Leaf :: Float -> Tree, so if Leaf is applied to a, then a :: Float) This gives us Float -> ???

Now we find the type of the lambda-less expression Leaf (a :: Float), which is Tree because Leaf :: Float -> Tree. Now we can add substitute Tree for ??? to get Float -> Tree, the actual type of func.

As you can see, we did that all by just looking at the source code. This means that no matter what, func will always have that type, so there is no need to check whether or not it does. In fact, the compiler will throw out all information about the type of func when it compiles your code, and your code will still work properly because of type-checking. (The caveat to this (Typeable) is pointed out in the other answer)

TL;DR: Haskell is statically typed, so func always has the type Float -> Tree, so asking how to check whether that is true doesn't make sense.

Upvotes: 0

luqui
luqui

Reputation: 60513

Well, there are a few answers, which zigzag in their answers to "is this possible".

  1. You could ask ghci

    ghci> :t func
    func :: Float -> Tree
    

    which tells you the type.

  2. But you said in your comment that you are wanting to write

    if func == Tree then 0 else 1
    

    which is not possible. In particular, you can't write any function like

    isTree :: a -> Bool
    isTree x = if x :: Tree then True else False
    

    because it would violate parametericity, which is a neat property that all polymorphic functions in Haskell have, which is explored in the paper Theorems for Free.

  3. But you can write such a function with some simple generic mechanisms that have popped up; essentially, if you want to know the type of something at runtime, it needs to have a Typeable constraint (from the module Data.Typeable). Almost every type is Typeable -- we just use the constraint to indicate the violation of parametericity and to indicate to the compiler that it needs to pass runtime type information.

    import Data.Typeable
    import Data.Maybe (isJust)
    
    data Tree = Leaf Float | ...
        deriving (Typeable) -- we need Trees to be typeable for this to work
    
    isTree :: (Typeable a) => a -> Bool
    isTree x = isJust (cast x :: Maybe Tree)
    
  4. But from my experience, you probably don't actually need to ask this question. In Haskell this question is a lot less necessary than in other languages. But I can't be sure unless I know what you are trying to accomplish by asking.

Upvotes: 3

Related Questions