Arc Forumnew | comments | leaders | submitlogin
lambdas different from inline functions, should I be surprised?
1 point by ambition 6021 days ago | 4 comments
Long story, bear with me.

I am working through SICP in Arc. I got to the Fixed Points of Functions section in Chapter 1. http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-12.html The example used sine and cosine. I decided to define my own using the accumulate function from earlier in SICP:

    (def accumulate (combiner null-value term a next b)
        (def iter (a result)
            (if (> a b) result
                (iter (next a) (combiner (term a) result))))
        (iter a null-value))
        
    (def sum (term a next b)
        (accumulate + 0 term a next b))
    (def product (term a next b)
        (accumulate * 1 term a next b))

    (def identity(v) v)
    (def inc(x) (+ x 1))

    (def factorial(n)
        (product identity 1 inc n))

    (def exp(n power)
        (product (fn (x) n) 1 inc power))

    (= iterations 100)

    ; Distinguisher is the difference between the cos and sine terms
    (def cos-sine-term(x n distinguisher)
            (/ (* (exp -1.0 n)(exp x (distinguisher n))) 
                  (factorial (distinguisher n))))

    (def cosine-distinguisher(n) (* 2 n))
    (def sine-distinguisher(n) (inc (cosine-distinguisher n)))

    (def cos-sine(x distinguisher)
        (sum (fn (n) (cos-sine-term x n distinguisher)) 0 inc iterations))

    (def cos(x)
        (cos-sine x cosine-distinguisher))

    (def sin(x)
        (cos-sine x sine-distinguisher))
Unfortunately it blew up. Yet when I tested each individual piece, no trouble.

I suspected that it had something to do with iter, and maybe that the wrong iter was being used at times.

So, I made a lambda version. (Halfway to a a Y Combinator! Too bad my Y Combinator version is broken)

    (def accumulate (combiner null-value term a next b)
        (((fn (f) 
            (fn (a result)
                (if (> a b) result
                     ((f f) (next a) (combiner (term a) result)))))
            (fn (f)
                (fn (a result)
                (if (> a b) result
                    ((f f) (next a) (combiner (term a) result))))))
            a 
            null-value))
This version works as expected.

I'm very new to this, but shouldn't the inline def version work the same as the lambda version?



4 points by almkglor 6021 days ago | link

(def foo ...) is a macro that means:

  (= foo (fn ...))
This means that:

    (def accumulate (combiner null-value term a next b)
        (def iter (a result)
    ...
'iter here is the global iter.

What you want to do is:

    (def accumulate (combiner null-value term a next b)
        (let iter (fn (a result)
            ....

-----

3 points by ambition 6021 days ago | link

I looked into this some more, and it looks like this is a difference between arc and scheme. I just wanted to put this out there for anyone else looking at Scheme materials through an Arc lens.

Arc:

    arc> (def fn2() (def i() (prn "fn2-i")) (i))
    #<procedure: fn2>
    arc> (fn2)
    fn2-i
    "fn2-i"
    arc> (def fn1() (def i() (prn-"fn1-i")) (fn2) (i))
    #<procedure: fn1>
    arc> (fn1)
    *** redefining i
    *** redefining i
    fn2-i
    fn2-i
    "fn2-i"
    
Scheme:

    > (define (fn2) (define (i) (print "fn2-i")) (i))
    > (fn2)
       "fn2-i"> (define (fn1) (define (i) (print "fn1-i")) (fn2) (i)) 
    > (fn1)
       "fn2-i""fn1-i">

-----

1 point by ambition 6021 days ago | link

Thanks!

-----

1 point by ambition 6021 days ago | link

For completeness (and in case someone can spot my mistake!) here's the broken Y Combinator version:

    (def Y2 (m) ((fn (f) (m (fn (a result) (f f) a result)))
          		(fn (f)	(m (fn (a result) (f f) a result)))))
    ; broken
    (def accumulate (combiner null-value term a next b)
    	((Y2 (fn (r)
    			(fn (a result)
    		   		(if (> a b) result
    		       		(r (next a) (combiner (term a) result))))))
    		a 
    		null-value))

-----