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

Jay Sulzberger jays at panix.com
Sun Jul 29 19:00:14 CEST 2012



On Sun, 29 Jul 2012, Ertugrul Söylemez <es at ertes.de>:

> "Costello, Roger L." <costello at mitre.org> wrote:
>
>> Recently I had a small epiphany: when creating functions, design them
>> to return functions rather than non-function values (Integer, Bool,
>> list, tuple, etc.).
>>
>> Here's why:
>>
>> Consider a function that returns, say, the integer four ( 4 ). The
>> type of the value returned by the function is this:
>>
>> 4 :: Num a => a
>
> This is not a Haskell function (even though it does actually compile to
> a function, unless you use specialization).  If it doesn't involve the
> (->) type constructor, then it's not a function.
>
>
>> That is, the value returned is not a function, it is a number.
>
> If you were to say x = 4, then 'x' is not a function.  It's a value
> equal to 4.  The equality sign in Haskell is not an assignment and
> doesn't introduce a function definition.  It introduces an equation, so
> "x = y" means that x is /the same/ as y.
>
>
>> However, there are advantages to returning a function rather than a
>> number.
>>
>> Recall the composition operator ( . )
>>
>> [...]
>
> There is a design pattern, where you compose functions ((->)) or
> function-like objects (Category/Arrow).  In this design pattern you work
> with constant functions to introduce values.  This is used in FRP, for
> example:
>
>    integral 0 . pure 4
>
> This is the integral of the constant 4 with respect to time.
>
>
>> Here's a data type that lifts non-function values to functions:
>>
>> [...]
>
> No, it doesn't.
>
>
>> data Lift a = Function a
>>                     deriving (Show)
>
> You have just reinvented an awkward version (data instead of newtype) of
> the identity functor, which is both a monad (a -> Identity a) and a
> comonad (Identity a -> a).  I don't see what it buys you given 'const'.
>
> Haskell is a language to study new ways of thinking, so it's great that
> you think, but you should really first learn the language properly.  You
> will find it helpful to learn the various type classes for categorical
> programming, in particular Category, Applicative and Arrow.  There is
> the reader monad, in which you would write the following:
>
>    fmap (^2) . fmap succ . pure 4
>
> or equivalently:
>
>    fmap ((^2) . succ) . pure 4
>
> The reader monad is defined as:
>
>    instance Applicative (e ->)
>    instance Functor (e ->)
>    instance Monad (e ->)
>
> Since (->) forms a category, you have composition and an identity
> morphism (the identity function).
>
> In other words, you have just invented an awkward way to write what can
> already be written nicely using existing stuff.
>
>
> Greets,
> Ertugrul
>
> -- 
> Not to be or to be and (not to be or to be and (not to be or to be and
> (not to be or to be and ... that is the list monad.

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.

What is this definition?  How polymorphic is it?  What implicit
constraints are on a?  Does "lazy vs eager" come in here?  Are
there options to ghc which might modify how Haskell handles the
definition?

Of course, my questions are too many and I hope just for some
indications of the first things a beginner should study.

oo--JS.


PS.  Below is a short Scheme session showing some of the behavior of Scheme.

SCM version 5d9, Copyright (C) 1990-2002 Free Software Foundation.
SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `(terms)' for details.
;loading /usr/local/lib/slib/require
;done loading /usr/local/lib/slib/require.scm
> (define mcf
   (lambda (a)
     (lambda (x) a)))
#<unspecified>
> (define const-17 (mcf 17))
#<unspecified>
> (const-17 "abc")
17
> (define const-1+ (mcf 1+))
#<unspecified>
> (const-1+ "abc")
#<CLOSURE <anon> "/usr/local/lib/scm/Init5d9.scm": (n) (+ n 1)>
> ((const-1+ "abc") 200)
201
> ((const-1+ 56) 200)
201
> (quit)
;EXIT

Process scheme finished




More information about the Beginners mailing list