[Haskell-cafe] Newbie Question on type constructors

Paul Hudak paul.hudak at yale.edu
Mon Nov 1 13:50:56 EST 2004


Ben Rudiak-Gould wrote:
 > Have I succeeded in reconciling our views?

Perhaps!  In particular, perhaps it's just a pedagogical issue.  Note 
that instead of:

data Shape = Circle Float
            | Square Float

the Haskell designers might have used the following syntax:

data Shape where
      Circle :: Float -> Shape
      Square :: Float -> Shape

which conveys exactly the same information, and makes it quite clear 
that Circle and Square are functions.  I often point this out to my 
students, because I find it less confusing than Haskell's data type 
declaration, where type constructors and value constructors are 
intermixed (i.e. "Circle Float").  Would this have been less confusing 
for you?

As for pattern matching, I think the key point relates to Keith 
Wansbrough's comment that an algebraic data type denotes an initial 
algebra.  If you want to retain referential transparency, each 
application of the function being pattern-matchined against must yield a 
unique value (i.e. "no confusion" as Keith describes it).  This is 
guaranteed with a constructor, but not with arbitrary functions.  So, 
another way to look at it is that constructors simply carve out a 
portion of the function space where this can be guaranteed.

That said, there are lots of interesting directions to pursue where 
pattern-matching against functions IS allowed (requiring higher-order 
unification and the like).  I suppose that topic is out of the scope of 
this discussion.

   -Paul


Ben Rudiak-Gould wrote:
> Paul Hudak wrote:
> 
>> Oh, I disagree with this point of view.  Circle is certainly a value, 
>> i.e. a full-fledged function, as Brian Beckman correctly surmised.
> 
> 
> Interesting. I don't claim that my viewpoint is the One True Path, but I 
> don't think it's wrong, either. I know you're interested in the teaching 
> of Haskell, and the fact remains that I *was* confused by data 
> constructors when I learned Haskell, and it *did* help me to stop 
> thinking of them as functions. Different people learn in different ways, 
> and that's how I learned; even now I find this view more natural than 
> the view of constructors as functions. The wording of the OP's article 
> made me think that he might be suffering from the same conceptual 
> problem, so I tried to suggest the approach which worked for me.
> 
>> The Haskell designers did not decide "for convenience" that Circle is 
>> the same as \x -> Circle x.  Rather, that's a fundamental law (the eta 
>> law, to be exact) of the lambda calculus, on which Haskell is based.
> 
> 
> I think you're begging the question here -- the eta law applies to 
> functions -- but maybe you're just elaborating on your view rather than 
> arguing for it, as I was. (I.e. I was elaborating, not arguing, when I 
> said that Circle was a function "for convenience".)
> 
>> The real reason that the Haskell designers chose to have constructors 
>> begin with a capital letter is to make pattern-matching clearer.
> 
> 
> Certainly it's odd to be able to match on the result of a function. 
> "case factorial (2*3) of factorial n -> ..." won't work, so it's 
> surprising that "case Circle (2*3) of Circle x -> ..." does, if Circle 
> is a function. On the other hand, if "Circle 6" is just a literal value, 
> it's not at all surprising that "case Circle 6 of Circle x -> ..." does 
> what it does. And, at least for me, that extends to "case Circle (2*3) 
> of Circle x -> ..." as well. (*) is being called in this example, and is 
> returning an entirely new value, 6, but Circle is just getting "added 
> on" to that result, and then stripped off again. There's a clear 
> symmetry between construction and deconstruction which doesn't seem 
> nearly as clear if Circle is seen as a function.
> 
> It occurs to me that when I talk about functions here, I am talking 
> about Haskell function values, not about functions as equations "f(x) = 
> ...". In particular, one cannot write an invert :: (a->b) -> Maybe 
> (b->a) which never returns a wrong answer, except for invert = const 
> Nothing -- this is why it makes no sense to me to imagine Circle as 
> being a Haskell *value*. I have no problem imagining it as a function in 
> a more abstract mathematical sense; it's just that Haskell function 
> values don't have that extra structure.
> 
> The view of Circle that I was trying to express is closer to Prolog 
> clauses. One can assert circle(1.2), and that assertion will match 
> circle(x), but it doesn't really make sense to assert circle, or to try 
> to match it.
> 
> Have I succeeded in reconciling our views?
> 
> -- Ben




More information about the Haskell-Cafe mailing list