[Haskell-cafe] Checking a value against a passed-in constructor?

Richard O'Keefe ok at cs.otago.ac.nz
Mon Jun 1 22:55:25 EDT 2009


On 2 Jun 2009, at 3:39 pm, Dan Cook wrote:

> Hi,
> (Relatively new to Haskell here ..)
>
> So I have the following:
>
> data MyVal =  Atom String
> 			| Bool Bool
>
> And I want to do something like this
>
> check :: (Bool -> MyVal) -> MyVal -> True
> check f (f x) = True
> check _ _ = False
>
> What that means is I want to pass a MyVal constructor and a MyVal,  
> and return True if the second argument was constructed with the first.

Yeek.  Why do you want to do _that_?

You could quite easily determine whether two values were
constructed with the _same_ constructor:

	check (Atom _) (Atom _) = True
	check (Bool _) (Bool _) = True
	check _        _        = False

and instead of passing in "a constructor" pass in
"an example of a term constructed by that constructor".
So instead of check Atom foo, do check (Atom undefined) foo
    instead of check Bool bar, do check (Bool undefined) bar

Another approach is to write a boolean function for each
constructor, e.g.,

	is_atom (Atom _) = True
	is_atom _        = False

	is_bool (Bool _) = True
	is_bool _	 = False

and pass one of these instead of a constructor:

	check :: (MyVal -> Bool) -> MyVal -> Bool
	check f x = f x

which makes the check function itself pointless.

>  More generally, I'd like to be able to do
>
> genCheck :: (* -> MyVal) -> MyVal -> True
> genCheck f (f x) = True
> genCheck _ _ = False
>
> So that I can pass in _any_ MyVal constructor and let the function  
> just check if the second argument was constructed with the first,  
> without caring which constructor it is.

There are some very high-powered things you can do in Haskell these
days which would let you get closer to this than most people would
be happy reading.  We can use the same idea of passing an example.
So given
	data Biffo x y z
	   = Ping x
	   | Pong y z
	   | Pang x y z

you can easily write

	check (Ping _)     (Ping _)     = True
	check (Pong _ _)   (Pong _ _)   = True
	check (Pang _ _ _) (Pang _ _ _) = True
	check _            _            = False

called as
	check (Ping undefined) foo
or	check (Pong undefined undefined) bar
or	check (Pang undefined undefined undefined)

or much better, go the Boolean function route:

	is_ping (Ping _) = True
	is_ping _        = False

	is_pong (Pong _ _) = True
	is_pong _          = False

	is_pang (Pang _ _ _) = True
	is_pang _            = False

and use one of these functions whenever you want something you
can use to check for a particular constructor.

There are various meta-programming ("Scrap Your Boilerplate",
"Template Haskell") approaches you can use to automate some of
these.

The first step is the step backwards where you ask "why am I
trying to do this?"




More information about the Haskell-Cafe mailing list