[Haskell-beginners] Here's why functions should return functions

Jay Sulzberger jays at panix.com
Mon Jul 30 21:48:31 CEST 2012

On Mon, 30 Jul 2012, Ertugrul Söylemez <es at ertes.de> wrote:

> Jay Sulzberger <jays at panix.com> wrote:
>> There is, in most sub-systems of mathematics, whether like recent type
>> theory or not, a general function, let us call it mcf which in Scheme
>> notation may be defined by executing
>> (define mcf
>>    (lambda (a)
>>      (lambda (x) a)))
>> Now in Haskell I know that one, perhaps the, parallel definition must
>> result in a polymorphic function.
> First let's ensure that we are talking about the same function.  I'm
> reading "mcf" as "make constant function".  From what I read the Haskell
> equivalent would be this function:
>    const a _ = a
> It may make it not fully polymorphic, but if you don't provide a type
> signature, then the following fully polymorphic type will be inferred:
>    const :: a -> b -> a

This is good.

>> What is this definition?
> Well, this is the constant function, though with slightly unusual (but
> sensible) semantics for Scheme.  Because Scheme syntax requires explicit
> currying the name "make constant function" would also be sensible.  It
> is because of the lack of side effects that we call the function simply
> 'const' in Haskell.  Otherwise most functions would be prefixed with
> "make".

Ah, yes.  Certainly all functions with more than one input.

>> What implicit constraints are on a?
> None.

I am encouraged by this.

>> Does "lazy vs eager" come in here?
> Yes.  Even though you have written a curried version of 'const' there,
> Scheme is still a strict language, which means that the result of the
> inner lambda will depend on its argument 'x'.  This means:
>    -- Haskell:
>    const a ⊥ = a
>    -- in other words:
>    loop = loop  -- an infinite loop
>    const a loop = a
>    ; Scheme:
>    ((mcf a) ⊥) = ⊥
>    (define (loop) (loop))  ; an infinite loop
>    ((mcf a) (loop)) = (loop)

Yes, I see, I think.

I think, if we were doing a finer analysis, we might write

((mcf a) (loop)) ~> [(mcf a) waiting] (loop)

where [ waiting] indicates that when loop finishes executing, and
returns, ah, something, perhaps nothing, the constant function
(mcf a) will accept that returned thing.  (To be clear: above
line is not Scheme nor indeed is it a phrase of any standard
programming system.)

We here avoid mentioning (\omega + 1) ;)

> This is the semantic difference.  To relate this to "lazy vs. eager"
> it's important to understand how a nonstrict language like Haskell is
> usually evaluated:  Lazy evaluation will defer the evaluation of the
> inner lambda's argument (which is an unnamed '_' here) until it is
> required.  Since it is never required it is never evaluated and the
> unevaluated thunk is garbage-collected immediately, unless it is used
> elsewhere.
> A strict language like Scheme is usually evaluated eagerly.  This means
> that the inner lambda is not entered, until the argument is fully
> evaluated.


>> Are there options to ghc which might modify how Haskell handles the
>> definition?
> There are optimization flags, which could change the performance of the
> definition, but a proper Haskell compiler like GHC must ensure that
> semantics are not changed.
>> Of course, my questions are too many and I hope just for some
>> indications of the first things a beginner should study.
> No worries.  I'm happy to help. =)
> Greets,
> Ertugrul

Thanks, Ertugrul!


More information about the Beginners mailing list