Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does type constructor pattern matching require the argument to be the constructor's type

For example, i want to write the following function:

isTree Leaf = "True"
isTree Node {} = "True"
isTree  _       = "False"

that takes any type and returns True only if an argument of type Tree a was passed. But this is impossible. Why?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

You can’t pattern match different types. Types don’t exist at runtime, they’re only there for the compiler to check your code, link the correct type class, etc..

It is possible to write a function that "takes any type"

isTree :: a -> Bool

but such a function can’t actually do anything at all with its argument. I mean, technically speaking you might be able to read the address and do arithmetic with it, but Haskell doesn’t allow that for good reasons.

At any rate you wouldn’t be able to do pattern matching, because two different types may use the same binary representation to express completely different things. It’s like, in assembly there’s no way to distinguish the values 121 and 'y', they’re just two different interpretations of the bit pattern 01111001.

Of course, some programming languages do explicitly store the type information along with each value, but this is generally redundant: if the code has been type checked, there isn’t any need for looking "what type does this value have", because the compiler has already made sure beforehand that any value that could possibly be given there does have the single appropriate type.

Of course, there are reasons why you might want to pass values of different types to a function. The simplest option is to use a variant type:

data TreeOrElse = YeahATree Tree
                | NopeNotATree (Int, [Double])

isTree :: TreeOrElse -> Bool
isTree (YeahATree _) = True
isTree (NopeNotATree _) = False

If you really want to permit passing any type and checking if it is particularly Tree (which is probably a bad idea), you also need to explicitly pass the information on. This is what Dynamic allows:

import Data.Dynamic

isTree :: Dynamic -> Bool

To implement this, you need your type to be an instance of the Typeable class

{-# LANGUAGE DeriveDataTypeable #-}

data Tree = ...
 deriving (Typeable, ...)

isTree t = case fromDynamic t :: Maybe Tree of
  Nothing -> False
  Just _ -> True
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading