Frank Tian
Frank Tian

Reputation: 807

How to write a function returns either Integer or Bool based on a user defined data type?

I am given a data type like the following

data Value = IntVal Integer |
             BoolVal Bool
             deriving Show

I am trying to write a function getVal that takes a Value and returns the actual value inside. I was trying to achieve with pattern matching

getVal (IntVal val) = val
getVal (Bool bool) = bool

But Haskell complains about the returning types Couldn't match expected type 'Integer' with actuall type 'Bool'

So I gave it a signature returns a type variable

getVar :: Value -> a

But it won't work either

Upvotes: 3

Views: 1924

Answers (4)

Mark Karpov
Mark Karpov

Reputation: 7599

Yes, this can be handled with help of type classes or GADTs or you can even use cast leveraging Data.Typeable. But all those thing are useful when you know Haskell well, and when you know what you're doing exactly.

In your case, you should really try to understand how Haskell works in general. Haskell is about imposing wise invariants that make it impossible to write “bad” programs (well, that's how I put it). This is done via type system, and without those invariants attached you cannot really do anything.

So now, you cannot do much with a thing of type a, because you don't know much about it. If you want to return value from function that can be either Int or Bool (that's actually possible see existential quantification), you will be able to perform actions on that value that can be performed on Int and on Bool. You can get textual representation of that value for example.

Chances are you want more than that. In this case you probably shouldn't try to return Int and Bool at the same time without a way to understand what exactly you have as a result.

So, you can do the following for example:

getVar :: Value -> Either Int Bool

Or you can just dispatch:

case Value of
  IntVal  x -> doWhatYouWantToDoWithInteger x
  BoolVal x -> doWhatYouWantToDoWithBoolean x

This is natural flow of Haskell. In every branch of program you now know what you're dealing with.

Hope it helps.

Upvotes: 10

Paul Johnson
Paul Johnson

Reputation: 17806

user3237465 and behzad.nouri have provided answers to your specific question. However I wonder if you are thinking by analogy with OO and dynamically typed languages. If you are taking "Value" as an argument to a function then you should use pattern matching to do the Right Thing with the value it holds. So suppose you are writing a function "showValue" to return the value as a string. I guess you are trying to do something like:

showValue :: Value -> String
showValue v = let v1 = getValue v in <something>

But that won't work in Haskell because the type system insists on knowing what type "v1" is. Instead you write it like this:

showValue (IntVal i) = "The Value is an integer " ++ show i
showValue (BoolVal b) = "The Value is a boolean " ++ show b

Upvotes: 2

effectfully
effectfully

Reputation: 12735

That's a job for GADTs:

{-# LANGUAGE GADTs #-}

data Value a where
    IntVal  :: Integer -> Value Integer
    BoolVal :: Bool    -> Value Bool

getVal :: Value a -> a
getVal (IntVal  i) = i
getVal (BoolVal b) = b

Upvotes: 3

behzad.nouri
behzad.nouri

Reputation: 78021

One way to do it is to use type-classes, to make a function polymorphic in return value:

\> :t getVal
getVal :: GetValue a => Value -> Maybe a

by a simple code as in bellow:

data Value = IntVal Integer
           | BoolVal Bool
             deriving Show

class GetValue a where
    getVal :: Value -> Maybe a

instance GetValue Integer where
    getVal (IntVal i) = Just i
    getVal          _ = Nothing

instance GetValue Bool where
    getVal (BoolVal b) = Just b
    getVal           _ = Nothing

and let the type-inference decide the right function:

\> import Data.Maybe (fromJust)
\> (3 +) .fromJust . getVal $ IntVal 5  -- getVal :: Value -> Maybe Integer
8
\> not . fromJust . getVal $ BoolVal False  -- getVal :: Value -> Maybe Bool
True

Upvotes: 4

Related Questions