Hello,

This is my first post here, and it's an odd one, I'll admit. Basically, I'm trying to translate the material in The Little MLer to Haskell, the TLMLer being an excellent types workout. So in SML I have this

datatype 'a shish = Bottom of 'a | Onion of 'a shish | Lamb of 'a shish | Tomato of 'a shish

and this

datatype rod =  Dagger | Fork | Sword

and then this SML function

fun is_veggie (Bottom (x)) = true
  | is_veggie (Onion (x)) = is_veggie (x)
  | is_veggie (Lamb (x)) = false
  | is_veggie (Tomato (x)) = is_veggie (x)


which has no problem handling tis

is_veggie (Onion(Tomato(Bottom(Dagger))))

Now, in Haskell I've translated this (with minor alterations) to

data Shish a = Holder a | Onion a (Shish a) | Lamb a (Shish a) | Tomato a (Shish a)
data Rod = Dagger | Fork | Sword

However, in Haskell these two expressions are different things entirely

meal4 = Tomato Dagger (Onion Fork (Lamb Spear (Holder Fork)))
meal5 = (Tomato (Onion (Lamb (Holder Fork))))

Here's my attempt at handling meal4 with a Haskell isVeggie

isVeggie (Holder (sh)) = True
isVeggie (Onion sh (sk)) = isVeggie sk
isVeggie (Tomato sh (sk)) = isVeggie sk
isVeggie (Lamb sh (sk)) = False

This works for meal4, but not for meal5. And yet in the SML world their is_veggie handles (Onion(Tomato(Bottom(Dagger)))) just fine. TLMLer says 

Onion (Tomato (Bottom (Dagger)))

belongs to the type rod shish, while in Haskell

Onion (Tomato (Holder (Dagger)))

is a bizarre nested beast due to the fact that the data constructor variable of Onion is Tomato (Holder (Dagger)) etc. etc.

Can a single Haskell version of isVeggie handle both meal4 and meal5? No? I thought so. But then how would a separate Haskell version of isVeggie handle meal5 -- or is it just too weird? Also, but not critical, how could the Haskell isVeggie be done with guards, i.e., just like a consed list is matched on (x:xs) in the recursion case? I can see that 1:2:3:[] and Onion (Tomato (Bottom (Dagger))) are both conses, but the latter I don't know how to break out into head and tail for a guard case where the individual food items were not mentioned explicitly. IOW, this doesn't work

isVeggieKebab :: Shish -> Bool
isVeggieKebab Holder (sk) = True
isVeggieKebab (shkb (sk)) | (shkb == Onion) || (shkb == Tomato) = isVeggieKebab sk
                        | otherwise = False


I'm feeling some doom and gloom about this project. Right at the start this seems to be an insurmountable difference between SML and Haskell type systems. Or I simply don't understand something fundamental here.

LB