Closure

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Closure

Matthew J. Williams
Good morning

What is a closure and, what purpose does it serve?

        Sincerely,
        MJW

Reply | Threaded
Open this post in threaded view
|

Closure

Magnus Therning
On Wed, Jul 29, 2009 at 2:02 AM, Matthew J.
Williams<[hidden email]> wrote:
> Good morning
>
> What is a closure and, what purpose does it serve?

This seems like a good explanation: http://www.haskell.org/haskellwiki/Closure

/M

--
Magnus Therning                        (OpenPGP: 0xAB4DFBA4)
magnus?therning?org          Jabber: magnus?therning?org
http://therning.org/magnus         identi.ca|twitter: magthe
Reply | Threaded
Open this post in threaded view
|

Closure

Matthew J. Williams

>Williams<[hidden email]> wrote:
> > Good morning
> >
> > What is a closure and, what purpose does it serve?
>
>This seems like a good explanation: http://www.haskell.org/haskellwiki/Closure
>
>/M
>
>Williams<[hidden email]> wrote:
How does a closure differ from a binding? An example or two would be nice. :-)

         Sincerely,
         MJW  

Reply | Threaded
Open this post in threaded view
|

Closure

Brent Yorgey-2
On Wed, Jul 29, 2009 at 09:11:02PM +0100, Matthew J. Williams wrote:

>
>> Williams<[hidden email]> wrote:
>> > Good morning
>> >
>> > What is a closure and, what purpose does it serve?
>>
>> This seems like a good explanation: http://www.haskell.org/haskellwiki/Closure
>>
>> /M
>>
>> Williams<[hidden email]> wrote:
> How does a closure differ from a binding? An example or two would be nice. :-)

A closure is essentially a binding, *together with* the enclosing
environment---the idea being that the binding may refer (via free
variables) to things in its environment.  The ability to have closures
is absolutely crucial to having first-class functions.

For example, consider this function:

  mkAdder :: Int -> (Int -> Int)
  mkAdder y = \x -> x + y

mkAdder takes an Int as an argument, and returns a function (Int ->
Int) as a result.  But take a look at the function it returns: \x -> x
+ y has a free variable (y) which refers to its environment.  So
really what you get when you call mkAdder with a particular argument
(say, 3) is a closure, containing the function \x -> x + y together
with the environment (y = 3).  

Of course, hopefully you have realized that mkAdder is really just
(+), written in a funny way!  So this isn't a contrived example;
closures are quite fundamental in Haskell.

With that said, on some level the idea of a closure is really just an
implementation detail---I wouldn't say that understanding it is of
fundamental importance in learning Haskell.  But learning things never
hurts (except when it does).

Hope this helps!
-Brent
Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Bastos
In article <[hidden email]>,
Brent Yorgey wrote:

> With that said, on some level the idea of a closure is really just an
> implementation detail---I wouldn't say that understanding it is of
> fundamental importance in learning Haskell.  But learning things never
> hurts (except when it does).

So it sounds correct to say that a closure is a function that brings
an environment with it, such as variables defined outside of it.

With this ability, we can construct functions on the fly because a
function can return a closure which is amended and, say, returned
again another closure more fully specified.

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Bastos
In article <h5tjgk$6d8$[hidden email]>,
Daniel Bastos wrote:

> In article <[hidden email]>,
> Brent Yorgey wrote:
>
>> With that said, on some level the idea of a closure is really just an
>> implementation detail---I wouldn't say that understanding it is of
>> fundamental importance in learning Haskell.  But learning things never
>> hurts (except when it does).
>
> So it sounds correct to say that a closure is a function that brings
> an environment with it, such as variables defined outside of it.
>
> With this ability, we can construct functions on the fly because a
> function can return a closure which is amended and, say, returned
> again another closure more fully specified.

Hello. This was actually a request for comments. Though I didn't say
it. Does that sound correct? Any comments? Thanks much.

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Heinrich Apfelmus
Daniel Bastos wrote:

>
>> So it sounds correct to say that a closure is a function that brings
>> an environment with it, such as variables defined outside of it.
>>
>> With this ability, we can construct functions on the fly because a
>> function can return a closure which is amended and, say, returned
>> again another closure more fully specified.
>
> Hello. This was actually a request for comments. Though I didn't say
> it. Does that sound correct? Any comments? Thanks much.

Yes, that's pretty much correct.

The simplest example of a closure is indeed

   foo = add 3

where

   add = \x y -> x + y

Reduction to weak head normal form yields

   foo = let x = 3 in \y -> x + y

which means that  foo  is a function  \y -> x + y  paired with the value
of the free variable  x .


Note that closures are an implementation detail. From a semantic point
of view,  add 3  can readily be understood as an ordinary function.



Regards,
apfelmus

--
http://apfelmus.nfshost.com

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Bastos
In article <h65p0h$rjl$[hidden email]>,
Heinrich Apfelmus wrote:

> The simplest example of a closure is indeed
>
>    foo = add 3
>
> where
>
>    add = \x y -> x + y

Question. This is actually equal to

add x y = x + y

But you wrote in terms of \. Why such preference?

> Reduction to weak head normal form yields
>
>    foo = let x = 3 in \y -> x + y
>
> which means that  foo  is a function  \y -> x + y  paired with the value
> of the free variable  x .

I see.

> Note that closures are an implementation detail. From a semantic point
> of view,  add 3  can readily be understood as an ordinary function.

This makes sense. Because, even in a language like C, a similar effect
can be achieved, no? For example

int plus(int x, int y) { return x + y; }

int plus3(int y) { plus(3, y); }

So, what I can't do in C, besides almost everything I can't do, is to
do this nicely like I do in Haskell. But we don't call this a
closure. In fact, we say C does not allow for closures. So what am I
missing?

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Fischer-4
Am Samstag 15 August 2009 18:07:08 schrieb Daniel Bastos:

> In article <h65p0h$rjl$[hidden email]>,
>
> Heinrich Apfelmus wrote:
> > The simplest example of a closure is indeed
> >
> >    foo = add 3
> >
> > where
> >
> >    add = \x y -> x + y
>
> Question. This is actually equal to
>
> add x y = x + y
>
> But you wrote in terms of \. Why such preference?
>
> > Reduction to weak head normal form yields
> >
> >    foo = let x = 3 in \y -> x + y
> >
> > which means that  foo  is a function  \y -> x + y  paired with the value
> > of the free variable  x .
>
> I see.
>
> > Note that closures are an implementation detail. From a semantic point
> > of view,  add 3  can readily be understood as an ordinary function.
>
> This makes sense. Because, even in a language like C, a similar effect
> can be achieved, no? For example
>
> int plus(int x, int y) { return x + y; }
>
> int plus3(int y) { plus(3, y); }
>
> So, what I can't do in C, besides almost everything I can't do, is to
> do this nicely like I do in Haskell. But we don't call this a
> closure. In fact, we say C does not allow for closures. So what am I
> missing?
>

You can't do

cmp :: a -> a -> a -> Ordering
cmp pivot x y = ...

funkyFun :: (a -> a -> a -> Ordering) -> [a] -> [a]
funkyFun _ [] = []
funkyFun c (x:xs) = x:sortBy (c x) xs

main = do
    args <- getArgs
    print $ funkyFun cmp (some pseudorandom list depending on args)

in C (at least not without some black magic).

The plus3 example is a "closure" which is hardcoded and available at compile time.
I think, to say that a language allows closures means it allows closures determined at run
time.
Reply | Threaded
Open this post in threaded view
|

Re: Closure

Brandon S Allbery KF8NH
In reply to this post by Daniel Bastos
On Aug 15, 2009, at 12:07 , Daniel Bastos wrote:

> This makes sense. Because, even in a language like C, a similar effect
> can be achieved, no? For example
>
> int plus(int x, int y) { return x + y; }
>
> int plus3(int y) { plus(3, y); }
>
> So, what I can't do in C, besides almost everything I can't do, is to
> do this nicely like I do in Haskell. But we don't call this a
> closure. In fact, we say C does not allow for closures. So what am I
> missing?


In C you have to declare it.  In Haskell you can just do it on the fly:

 > map (add 3) [1..10]

or indeed

 > map (+3) [1..10]

(The above is actually a "section", a closure created from an infix  
function.  The difference is that I can specify either side of the  
operator, whereas to specify arguments other than the first for a  
regular function I must either coerce it into infix with `` or use the  
"flip" function to rearrange arguments.)

--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [hidden email]
system administrator [openafs,heimdal,too many hats] [hidden email]
electrical and computer engineering, carnegie mellon university    KF8NH


-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 195 bytes
Desc: This is a digitally signed message part
Url : http://www.haskell.org/pipermail/beginners/attachments/20090815/c71a43c5/PGP.bin
Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Bastos
In article <[hidden email]>,
Brandon S. Allbery KF8NH wrote:

> In C you have to declare it.  

The word would be `define'?

> In Haskell you can just do it on the fly:
>
> > map (add 3) [1..10]

I see. Just like we can create an integer on the fly in C, in Haskell
we can create functions on the fly. I guess that's quite a difference.

> or indeed
>
> > map (+3) [1..10]
>
> (The above is actually a "section", a closure created from an infix  
> function.  The difference is that I can specify either side of the  
> operator, whereas to specify arguments other than the first for a  
> regular function I must either coerce it into infix with `` or use the  
> "flip" function to rearrange arguments.)

And is this mere syntax sugar?

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Bastos
In reply to this post by Daniel Fischer-4
In article <[hidden email]>,
Daniel Fischer wrote:

> The plus3 example is a "closure" which is hardcoded and available at
> compile time.  I think, to say that a language allows closures means
> it allows closures determined at run time.

Hm. But does Haskell allow me to define a function at run time? I know
Lisp can, since a function is just a data structure which we can put
together at run time. But how about Haskell?

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Fischer-4
Am Samstag 15 August 2009 19:06:42 schrieb Daniel Bastos:

> In article <[hidden email]>,
>
> Daniel Fischer wrote:
> > The plus3 example is a "closure" which is hardcoded and available at
> > compile time.  I think, to say that a language allows closures means
> > it allows closures determined at run time.
>
> Hm. But does Haskell allow me to define a function at run time? I know
> Lisp can, since a function is just a data structure which we can put
> together at run time. But how about Haskell?

Depends on how you interpret it.
In the sense of

... let foo = \y -> f x y in map foo list

where the value of x is supplied at run time (and more complicated constructions depending
on run time values), sure.
If you write a good parser, you can also

do  putStrLn "Please enter function code:"
    code <- getLine
    let fun = parseFunction code
    use fun   -- may segfault if the entered code isn't good

In which (other) ways can you construct functions at run time in Lisp?


Reply | Threaded
Open this post in threaded view
|

Re: Closure

Heinrich Apfelmus
In reply to this post by Daniel Bastos
Daniel Bastos wrote:

> Heinrich Apfelmus wrote:
>
>> The simplest example of a closure is indeed
>>
>>    foo = add 3
>>
>> where
>>
>>    add = \x y -> x + y
>
> Question. This is actually equal to
>
> add x y = x + y
>
> But you wrote in terms of \. Why such preference?

I wanted to emphasize that  add  is a value just like  4  or  "baz" ,
i.e. that it's not very different from writing say

    add = "baz"

>> Note that closures are an implementation detail. From a semantic point
>> of view,  add 3  can readily be understood as an ordinary function.
>
> This makes sense. Because, even in a language like C, a similar effect
> can be achieved, no? For example
>
> int plus(int x, int y) { return x + y; }
>
> int plus3(int y) { plus(3, y); }
>
> So, what I can't do in C, besides almost everything I can't do, is to
> do this nicely like I do in Haskell. But we don't call this a
> closure. In fact, we say C does not allow for closures. So what am I
> missing?

A litmus test for being a functional language is the ability to define
function composition

   f . g = \x -> f (g x)

This is not possible in C; mainly because functions cannot be defined
locally, they have to be declared at the top-level.

(I think this test is due to Lennart Augustsson, but I can't find a
reference on the web right now.)


Hm... this means that Brent's example

   foo x = add
       where
       add y = x + y

is actually a much better demonstration of a closure than the one I
gave. Yes, I think this one is impossible to write in C.


Regards,
apfelmus

--
http://apfelmus.nfshost.com

Reply | Threaded
Open this post in threaded view
|

Re: Closure

Daniel Bastos
In reply to this post by Daniel Fischer-4
In article <[hidden email]>,
Daniel Fischer wrote:

>> [Does] Haskell allow me to define a function at run time? I know
>> Lisp can, since a function is just a data structure which we can
>> put together at run time. But how about Haskell?

[...]

> If you write a good parser, you can also
>
> do  putStrLn "Please enter function code:"
>     code <- getLine
>     let fun = parseFunction code
>     use fun   -- may segfault if the entered code isn't good
>
> In which (other) ways can you construct functions at run time in Lisp?

None. I guess the only difference, if so considered, is that since
Lisp is so much syntactically simpler, it's easy to write a parser for
it, and I guess most implementations already bring one for ya. And
that's nice. It allows for the code that write code, which sounds
great. But anyway, my interest here was understanding Haskell better,
which I now do. Thanks for all inputs in this subthread.