[Haskell-cafe] SML vs Haskell types

Galaxy Being borgauf at gmail.com
Fri Mar 12 22:01:18 UTC 2021


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.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20210312/497df706/attachment.html>

More information about the Haskell-Cafe mailing list