Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Here's why functions should return functions (Costello, Roger L.)
2. Re: Here's why functions should return functions
(Ertugrul S?ylemez)
3. Re: Here's why functions should return functions (Thiago Negri)
4. Re: Here's why functions should return functions
(Costello, Roger L.)
5. Re: Here's why functions should return functions
(Ertugrul S?ylemez)
6. Re: Here's why functions should return functions (Jay Sulzberger)
7. Fwd: Here's why functions should return functions
(Antoine Latter)
----------------------------------------------------------------------
Message: 1
Date: Sun, 29 Jul 2012 12:15:02 +0000
From: "Costello, Roger L." <[email protected]>
Subject: [Haskell-beginners] Here's why functions should return
functions
To: "[email protected]" <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="us-ascii"
Hi Folks,
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
That is, the value returned is not a function, it is a number.
However, there are advantages to returning a function rather than a number.
Recall the composition operator ( . )
Its operands are functions, e.g.
(+1) . (*3)
In programming, one school of thought is that programs should be written as a
chain of function compositions:
a . b . c . d . e . f
Composition is intimately connected to a branch of mathematics called Category
Theory:
Category theory is based on composition as a fundamental
operation in much the same way that classical set theory is
based on the 'element of' or membership relation. ["Category
Theory for Computing Science" by Michael Barr and Charles
Wells]
By designing programs in this fashion--as a chain of compositions--you have
Category Theory's vast body of knowledge to help you and give rigor to your
programs.
Let's revisit the function mentioned above, the one that returns the integer
four ( 4 ). If the function were to return the four cloaked in a function then
that returned value could be used in a composition. That would very useful.
Here's a data type that lifts non-function values to functions:
data Lift a = Function a
deriving (Show)
The constructor ( Function ) is a function, as its type signature shows:
Function :: a -> Lift a
So rather than returning 4, return Function 4. Here's a function that converts
any value to a function:
lift :: a -> Lift a
lift = Function
Thus, lift 4 returns Function 4
Given the Lift data type and the lift function we can now start chaining
functions together. Here the value four is lifted and then composed with a
successor function:
(successor . lift) 4 returns Function 5
where successor is defined as:
successor :: Num a => Lift a -> Lift a
successor (Function a) = lift (a + 1)
Notice that successor returns a function, not a non-function value.
Consequently, the result of successor can also be used in a composition.
For example, here the value four is lifted, composed with successor, and then
square is applied:
(square . successor . lift) 4 returns Function 25
where square is defined as:
square :: Num a => Lift a -> Lift a
square (Function a) = lift (a * a)
Once again notice that square also returns a function, not a non-function
value. Consequently, the result of square can be used in a composition.
At some point we are finished manipulating the value four and want to just see
the result, not the result wrapped in a constructor. So we can create a
function to return the non-function value:
value :: Lift a -> a
value (Function a) = a
Here's an example:
(value . square . successor . lift) 4 returns 25
Comments welcome.
/Roger
------------------------------
Message: 2
Date: Sun, 29 Jul 2012 14:42:18 +0200
From: Ertugrul S?ylemez <[email protected]>
Subject: Re: [Haskell-beginners] Here's why functions should return
functions
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"
"Costello, Roger L." <[email protected]> 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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20120729/f090b8a1/attachment-0001.pgp>
------------------------------
Message: 3
Date: Sun, 29 Jul 2012 10:45:22 -0300
From: Thiago Negri <[email protected]>
Subject: Re: [Haskell-beginners] Here's why functions should return
functions
To: [email protected]
Message-ID:
<cablnezuyqsmf9_o_xh5efrpb1eawumhfi1dwf-_-qed8j3h...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8
@Ertugrul, you don't need to be rude.
@Costello,
I like your idea. But I don't see an advantage to using "Function 4"
over simply "4":
What's the advantage of using this:
(value . square . sucessor . lift) 4
data Lift a = Function a
lift = Function
sucesor (Function a) = lift (a + 1)
square (Function a) = lift (a * a)
value (Function a) = a
Over this:
(square . sucessor) 4
sucessor = (+1)
square a = a * a
For me, it looks like we are wrapping a value inside a container and
dewrapping it every time we want to use it's value, then rewrap to
return.
Could you elaborate an example that your Lift a datatype is better
suited than just the raw value?
I can only see the use of a value lifted as a function when you want
to get the same result no matter what are the chain of functions, for
example, the use of the const function:
const 4 . square . sucessor $ 4
Thiago.
------------------------------
Message: 4
Date: Sun, 29 Jul 2012 14:30:59 +0000
From: "Costello, Roger L." <[email protected]>
Subject: Re: [Haskell-beginners] Here's why functions should return
functions
To: "[email protected]" <[email protected]>
Message-ID:
<[email protected]>
Content-Type: text/plain; charset="us-ascii"
Thiago Negri wrote:
> What's the advantage of using this:
> (value . square . successor . lift) 4
> data Lift a = Function a
> lift = Function
> successor (Function a) = lift (a + 1)
> square (Function a) = lift (a * a)
> value (Function a) = a
>
> Over this:
> (square . successor) 4
> successor = (+1)
> square a = a * a
Oops!
There's no advantage, that I can see, of the former over the latter.
Thanks Thiago for pointing this out. This is very helpful. It helps me to avoid
continuing on a wrong course of thought.
/Roger
------------------------------
Message: 5
Date: Sun, 29 Jul 2012 16:55:06 +0200
From: Ertugrul S?ylemez <[email protected]>
Subject: Re: [Haskell-beginners] Here's why functions should return
functions
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"
Thiago Negri <[email protected]> wrote:
> @Ertugrul, you don't need to be rude.
Sorry if this sounded rude, but it really wasn't supposed to be. As
said, I liked Costello's attempt. I just found that the solution is
already in the base library in a way that doesn't require wrapping
things up in a constructor.
> @Costello,
>
> I like your idea. But I don't see an advantage to using "Function 4"
> over simply "4":
>
> What's the advantage of using this:
> (value . square . sucessor . lift) 4
> data Lift a = Function a
> lift = Function
> sucesor (Function a) = lift (a + 1)
> square (Function a) = lift (a * a)
> value (Function a) = a
>
> Over this:
> (square . sucessor) 4
> sucessor = (+1)
> square a = a * a
I think that Costello is really referring to something called
function-level programming where you don't have values, but only
so-called functionals and composition. A value is then represented by a
constant function, which is exactly what 'const' and 'pure' are.
This is the essence of SKI calculus. It gets rid of all lambda
abstractions. The remainder is then an (unintelligible) expression of S
and K applications, but Haskell also has the power of Category, so this
can actually become readable code.
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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20120729/1583282c/attachment-0001.pgp>
------------------------------
Message: 6
Date: Sun, 29 Jul 2012 13:00:14 -0400 (EDT)
From: Jay Sulzberger <[email protected]>
Subject: Re: [Haskell-beginners] Here's why functions should return
functions
To: [email protected]
Message-ID: <[email protected]>
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
On Sun, 29 Jul 2012, Ertugrul S??ylemez <[email protected]>:
> "Costello, Roger L." <[email protected]> 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
------------------------------
Message: 7
Date: Sun, 29 Jul 2012 13:04:12 -0500
From: Antoine Latter <[email protected]>
Subject: [Haskell-beginners] Fwd: Here's why functions should return
functions
To: Beginners Haskell <[email protected]>
Message-ID:
<cakjsnqfrfxorwe7pkvsfuy-umvybwg5k_2fdi4xkks1v79m...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8
Oops, I forgot to "reply-all"
---------- Forwarded message ----------
From: Antoine Latter <[email protected]>
Date: Sun, Jul 29, 2012 at 1:03 PM
Subject: Re: [Haskell-beginners] Here's why functions should return functions
To: Jay Sulzberger <[email protected]>
On Sun, Jul 29, 2012 at 12:00 PM, Jay Sulzberger <[email protected]> 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.
>
> 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?
>
I think this is it:
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:const
It's definitions is:
const x _ = x
Antoine
> 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
>
>
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 49, Issue 31
*****************************************