[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