Checking a value against a passed-in constructor?

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. 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. What is the preferred way to do this, since neither of those functions compile? Cheers, - Dan

Hi Dan,
On Mon, Jun 1, 2009 at 8:39 PM, Dan Cook
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
You may be confusing yourself here on one point. The type 'Bool' is already defined by the prelude, but the data constructor is not. So you are able to create a data constructor for MyVal that is called "Bool" and contains a Bool. I think this distinction is leading to the next probem I see. Type signatures have to contain types and not values in Haskell. 'True' is a value so it can't be placed in the type signature. The type of True is Bool. So I think you meant to ask about: check :: (Bool -> MyVal) -> MyVal -> Bool Now if you define this function the first parameter can be any function Bool -> MyVal, not just the data constructors of MyVal. Also, the type of Atom :: String -> MyVal so you can't even pass it to 'check'.
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. 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.
This strikes me as a job for template haskell, but the use of TH is beyond what I can explain :)
What is the preferred way to do this, since neither of those functions compile?
My preferred way, is just to define isAtom and isBool both with type MyVal -> Bool and use them where I need them. There are a number of tools to generate such things like DrIFT, TH, and maybe some others? I hope that helps, Jason

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?"

Hi Richard,
Yeek. Why do you want to do _that_?
Heh. I've got a parser and I want to check what I've parsed (it's an exercise in Write Yourself a Scheme in 48 Hours).
check (Atom _) (Atom _) = True check (Bool _) (Bool _) = True check _ _ = False
Yes I came up with this too, but it seemed ugly to create unnecessary new values just to take them apart again.
is_atom (Atom _) = True is_atom _ = False
This is nicer. It still requires listing out the possible constructors (Bool, Atom ... the real code obviously has more). I don't like that, because I've already listed them out once, in the type declaration itself. Surely, I shouldn't have to list them out again?
There are various meta-programming ("Scrap Your Boilerplate", "Template Haskell") approaches you can use to automate some of these.
You hit the nail on the head. "Why I am doing this" is because of boilerplate. Boilerplate gives me rashes and bulbous spots on the nose. Consider the following Ruby code: def check(zeClass, zeValue) zeValue.is_a? zeClass end This does not require a new function for every class defined in Ruby. (To be fair, though, the class of a Ruby object tells you precious little, compared to a Haskell type constructor). I figured there would be a clever Haskell idiom that would give me a similarly concise route. Does it really require Template Haskell? I can barely parse regular Haskell as it is.. Cheers, - Dan

On Tue, Jun 2, 2009 at 3:50 AM, Dan
You hit the nail on the head. "Why I am doing this" is because of boilerplate. Boilerplate gives me rashes and bulbous spots on the nose.
Consider the following Ruby code:
def check(zeClass, zeValue) zeValue.is_a? zeClass end
This does not require a new function for every class defined in Ruby. (To be fair, though, the class of a Ruby object tells you precious little, compared to a Haskell type constructor).
I figured there would be a clever Haskell idiom that would give me a similarly concise route. Does it really require Template Haskell? I can barely parse regular Haskell as it is..
So the question is, why do you need to know if x is an Atom or a Bool? The Haskell idiom is to pattern match and just do what you want with the data: f (Atom s) = ... f (Bool b) = ... instead of f x = if isAtom x then ... atomData x ... else ... boolData x ... Alternatively, you can define a fold[1] once: myval :: MyVal -> (Bool -> a) -> (String -> a) -> a myval (Bool b) bool atom = bool b myval (Atom s) bool atom = atom s f x = myval bool atom where bool b = ... atom s = ... This is a small amount of boilerplate that you write once for each type; it's possible to automate it with TH, but usually it's not worth it, in my opinion. Coming from Ruby (the same route I took to get to Haskell!), you should be aware that Haskell does have somewhat more "boilerplate" than Ruby, but it has its benefits as well. I am a convert to the Church of Purity and Type-Safety :) And you can use type classes for many metaprogramming tasks. -- ryan [1] "fold" here is the general term for this type of function. Examples are foldr: http://haskell.org/ghc/docs/latest/html/libraries/base/src/GHC-Base.html#fol... maybe: http://haskell.org/ghc/docs/latest/html/libraries/base/src/Data-Maybe.html#m... either: http://haskell.org/ghc/docs/latest/html/libraries/base/src/Data-Either.html#...

Ryan Ingram wrote:
Dan
wrote: I figured there would be a clever Haskell idiom that would give me a similarly concise route. Does it really require Template Haskell? I can barely parse regular Haskell as it is..
[...]
Alternatively, you can define a fold[1] once:
myval :: MyVal -> (Bool -> a) -> (String -> a) -> a myval (Bool b) bool atom = bool b myval (Atom s) bool atom = atom s
f x = myval bool atom where bool b = ... atom s = ...
In terms of boilerplate, this is often far and away the cleanest solution. I highly recommend if for Write Yourself A Scheme. The one place where it falls down is when, for whatever reason, you end up having collections of MyVals which can't sensibly use some set of constructors. One common example is for type-checking compilers where you guarantee that ill-typed MyVals cannot be constructed (rather than doing a verification pass after construction to ensure they're well-typed). If your type has this problem, using the fold approach often means writing dummy functions to throw errors on invalid inputs, which in turn means sacrificing much of the type safety you'd like (even if you use something like the Maybe or Error monads instead of _|_). A canonical Haskell trick here is to use GADTs to maintain your type invariants, rather than using plain ADTs. This technique isn't really suitable for a first pass at learning Haskell though.
[1] "fold" here is the general term for this type of function. Examples are foldr: http://haskell.org/ghc/docs/latest/html/libraries/base/src/GHC-Base.html#fol... maybe: http://haskell.org/ghc/docs/latest/html/libraries/base/src/Data-Maybe.html#m... either: http://haskell.org/ghc/docs/latest/html/libraries/base/src/Data-Either.html#...
Two more good resources for folds are: * http://knol.google.com/k/edward-kmett/catamorphisms/ This has an implementation in Control.Morphism.Cata from category-extras[1], though the documentation is scarce. If you're interested in the theory of why folds look and work the way they do, then this knol is the best starting point. If you're familiar with OOP, a catamorphism is extremely similar to the recursive Visitor pattern. The big difference you'll see between this generic solution and specialized catamorphisms (foldr, maybe, either,...) is that the specialized versions unpack the Algebra into separate arguments. Also, this generic solution defines MyVal types with open-recursive functors and explicit fixed-point operators, whereas the specialized versions just use Haskell's regular ability to define recursive types (since the result of |fmap (cata f)| is consumed immediately). Don't let these trees obscure the forest. * http://www.cs.nott.ac.uk/~wss/Publications/DataTypesALaCarte.pdf This paper presents an innovative solution to the "expression problem" of defining an open set of constructors for a type. It uses the same open-recursive functor trick as above and may provide some illustration of why we may want to bother with it. If you're hungry for more details, there's an interesting discussion of the paper at [2]. [1] http://hackage.haskell.org/packages/archive/category-extras/ [2] http://wadler.blogspot.com/2008/02/data-types-la-carte.html -- Live well, ~wren
participants (6)
-
Dan
-
Dan Cook
-
Jason Dagit
-
Richard O'Keefe
-
Ryan Ingram
-
wren ng thornton