Confusion over currying, , lambda, and closures

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

Confusion over currying, , lambda, and closures

Lawrence Bottorff-2
I have these three versions of addition

addA x y = x + y
addB x = \y -> x + y
addC = \x -> \y -> x + y

and all three add two arguments just fine

> addA 2 3
5
> addB 2 3
5
> addC 2 3
5

but I can't see how addB and addC are actually accomplishing this. addA is currying, which I don't fully follow. addC I understand beta reduction-wise

(\x -> \y -> x + y) 2 3
(\y -> 2 + y) 3
(2 + 3)
5

but I don't understand addB and what steps are happening currying/beta reduction-wise. Can someone break down the steps with addA and addB?

LB



_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Confusion over currying, , lambda, and closures

Bob Ippolito
The steps and semantics are the same, the only meaningful difference is syntax.

These two definitions are indistinguishable:

f x = y
f = \x -> y

In basically the same way that these two expressions are:

(+) 1 2
1 + 2

In Haskell there are many cases where a more convenient but equivalent syntax exists to express certain terms. This is referred to as syntax sugar.

On Wed, Dec 23, 2020 at 19:12 Lawrence Bottorff <[hidden email]> wrote:
I have these three versions of addition

addA x y = x + y
addB x = \y -> x + y
addC = \x -> \y -> x + y

and all three add two arguments just fine

> addA 2 3
5
> addB 2 3
5
> addC 2 3
5

but I can't see how addB and addC are actually accomplishing this. addA is currying, which I don't fully follow. addC I understand beta reduction-wise

(\x -> \y -> x + y) 2 3
(\y -> 2 + y) 3
(2 + 3)
5

but I don't understand addB and what steps are happening currying/beta reduction-wise. Can someone break down the steps with addA and addB?

LB


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Confusion over currying, , lambda, and closures

Francesco Ariis
In reply to this post by Lawrence Bottorff-2
Il 23 dicembre 2020 alle 21:12 Lawrence Bottorff ha scritto:

> I have these three versions of addition
>
> addA x y = x + y
> addB x = \y -> x + y
> addC = \x -> \y -> x + y
>
> […]
>
> I can't see how addB and addC are actually accomplishing this. addA is
> currying, which I don't fully follow.

Parameters on the left-hand side of a function definition can always be
expressed as a lambda, by «plucking» them from the rightmost one

    addA x y = x + y
    addA x = \y -> x + y
    addA = \x -> \y -> x + y  -- those three are equal!

Intuitively you can say that first we are binding the patterns in the
function definition and then the one left in the lambda right-hand side
(if any). So:

    add 3 5
        addA x = \y -> x + y   3 5
        \y -> 3 + y            5
        3 + 5

I suspect what the book is trying to teach you is that you can partially
apply a function and pass it around merrily:

    map (addA 3) [1, 2, 3]

So by writing `addA 3` we obtain:

    addA :: Int -> Int -> Int
    addA :: Int -> (Int -> Int)        -- can also be written like this
                                       -- since `(->)` is associates to
                                       -- the right
    add3 :: Int -> Int                 -- applying addA to 3

another function with one parameter less. Once everything is applied, you
will get your result!
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Confusion over currying, , lambda, and closures

Jay Sulzberger
In reply to this post by Lawrence Bottorff-2

On Wed, 23 Dec 2020, Lawrence Bottorff <[hidden email]> wrote:

> I have these three versions of addition
>
> addA x y = x + y
> addB x = \y -> x + y
> addC = \x -> \y -> x + y
>
> and all three add two arguments just fine
>
>> addA 2 3
> 5
>> addB 2 3
> 5
>> addC 2 3
> 5
>
> but I can't see how addB and addC are actually accomplishing this. addA is
> currying, which I don't fully follow. addC I understand beta reduction-wise
>
> (\x -> \y -> x + y) 2 3
> (\y -> 2 + y) 3
> (2 + 3)
> 5
>
> but I don't understand addB and what steps are happening currying/beta
> reduction-wise. Can someone break down the steps with addA and addB?
>
> LB

Dear Lawrence Bottorf, your questions are delightful!

Heaven forwarding, I will respond more fully and clearly.

The questions you ask strike at the heart of the issue:

   Why is Haskell so hard to learn?

I offer no decent answer here, but I give below a transcript of an
incoherent session with ghci on panix3.panix.com,

  panix3% ghci --version
  The Glorious Glasgow Haskell Compilation System, version 7.8.4
  panix3% uname -a
  NetBSD panix3.panix.com 9.0 NetBSD 9.0 (PANIX-XEN-USER) #1: Sun May  3 21:15:18 EDT 2020  [hidden email]:/misc/obj64/misc/devel/netbsd/9.0/src/sys/arch/amd64/compile/PANIX-XEN-USER amd64
  panix3%


Below is the whole transcript of the session.  Note two things:

1. I do not know ghci.

2. I failed to ask the ':t" questions in the right order, for a good
training video.

But I hope the transcript is helpful.

oo--JS.


   bash-5.0$ ghci
   GHCi, version 7.8.4: http://www.haskell.org/ghc/  :? for help
   Loading package ghc-prim ... linking ... done.
   Loading package integer-gmp ... linking ... done.
   Loading package base ... linking ... done.
   Prelude> let addA x y = x + y
   Prelude> addA

   <interactive>:6:1:
       No instance for (Show (a0 -> a0 -> a0))
         arising from a use of `print'
       In a stmt of an interactive GHCi command: print it
   Prelude> print addA

   <interactive>:7:1:
       No instance for (Show (a0 -> a0 -> a0))
         arising from a use of `print'
       In the expression: print addA
       In an equation for `it': it = print addA

   <interactive>:7:7:
       No instance for (Num a0) arising from a use of `addA'
       The type variable `a0' is ambiguous
       Note: there are several potential instances:
         instance Num Double -- Defined in `GHC.Float'
         instance Num Float -- Defined in `GHC.Float'
         instance Integral a => Num (GHC.Real.Ratio a)
           -- Defined in `GHC.Real'
         ...plus three others
       In the first argument of `print', namely `addA'
       In the expression: print addA
       In an equation for `it': it = print addA
   Prelude> let addA x y = x + y
   Prelude> print it

   <interactive>:9:7:
       Not in scope: `it'
       Perhaps you meant `id' (imported from Prelude)
   Prelude> addA

   <interactive>:10:1:
       No instance for (Show (a0 -> a0 -> a0))
         arising from a use of `print'
       In a stmt of an interactive GHCi command: print it
   Prelude> addA 7

   <interactive>:11:1:
       No instance for (Show (a0 -> a0)) arising from a use of `print'
       In a stmt of an interactive GHCi command: print it
   Prelude> addA 7 5
   12
   Prelude> (addA 7)

   <interactive>:13:1:
       No instance for (Show (a0 -> a0)) arising from a use of `print'
       In a stmt of an interactive GHCi command: print it
   Prelude> :t (addA 7)
   (addA 7) :: Num a => a -> a
   Prelude> :t addA
   addA :: Num a => a -> a -> a
   Prelude> :t addA 7
   addA 7 :: Num a => a -> a
   Prelude> :t addA 7 5
   addA 7 5 :: Num a => a
   Prelude> let addB x = \y -> x + y
   Prelude> :t addB
   addB :: Num a => a -> a -> a
   Prelude> :t addB 7
   addB 7 :: Num a => a -> a
   Prelude> :t (addB 7)
   (addB 7) :: Num a => a -> a
   Prelude> :t addB 7 5
   addB 7 5 :: Num a => a
   Prelude> let addC = \x -> \y -> x + y
   Prelude> :t addC
   addC :: Num a => a -> a -> a
   Prelude> :t (addC)
   (addC) :: Num a => a -> a -> a
   Prelude> :t addC 7
   addC 7 :: Num a => a -> a
   Prelude> :t (addC 7)
   (addC 7) :: Num a => a -> a
   Prelude> :t addC 7 5
   addC 7 5 :: Num a => a
   Prelude> addC 7 5
   12
   Prelude> (addC 7 5)
   12
   Prelude> (exit)

   <interactive>:31:2: Not in scope: `exit'
   Prelude>
   Leaving GHCi.
   bash-5.0$


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Confusion over currying, , lambda, and closures

Joel Neely
In reply to this post by Lawrence Bottorff-2
Hi, Lawrence,

Would it help you to think of addB as a function that takes its argument x and returns a function/lambda that adds x to the argument to which that returned function is applied?

Best wishes,
-jn-

On Wed, Dec 23, 2020 at 9:12 PM Lawrence Bottorff <[hidden email]> wrote:
I have these three versions of addition

addA x y = x + y
addB x = \y -> x + y
addC = \x -> \y -> x + y

and all three add two arguments just fine

> addA 2 3
5
> addB 2 3
5
> addC 2 3
5

but I can't see how addB and addC are actually accomplishing this. addA is currying, which I don't fully follow. addC I understand beta reduction-wise

(\x -> \y -> x + y) 2 3
(\y -> 2 + y) 3
(2 + 3)
5

but I don't understand addB and what steps are happening currying/beta reduction-wise. Can someone break down the steps with addA and addB?

LB


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners