[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.

Yes.

>
>
>> 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!

oo--JS.



More information about the Beginners mailing list