factorial function for Church numerals - clojure

I'm trying to implement the factorial lambda expression as described in the book Lambda-calculus, Combinators and Functional Programming
The way it's described there is :
fact = (Y)λf.λn.(((is-zero)n)one)((multiply)n)(f)(predecessor)n
Y = λy.(λx.(y)(x)x)λx.(y)(x)x
where
(x)y is equivalent to (x y) and
(x)(y)z is equivalent to (x (y x)) and
λx.x is equivalent to (fn [x] x)
and is-zero, one, multiply and predecessor are defined for the standard church numerals. Actual definitions here.
I translated that to the following
(defn Y-mine [y] ; (defn Y-rosetta [y]
((fn [x] (y (x x))) ; ((fn [f] (f f))
(fn [x] ; (fn [f]
(y ; (y (fn [& args]
(x x))))) ; (apply (f f) args))))))
and
(def fac-mine ; (def fac-rosetta
(fn [f] ; (fn [f]
(fn [n] ; (fn [n]
(is-zero n ; (if (zero? n)
one ; 1
(multiply n (f (predecessor n))))))) ; (* n (f (dec n)))))))
The commented out versions are the equivalent fac and Y functions from Rosetta code.
Question 1:
I understand from reading up elsewhere that the Y-rosetta β-reduces to Y-mine. In which case why is it preferable to use that one over the other?
Question 2:
Even if I use Y-rosetta. I get a StackOverflowError when I try
((Y-rosetta fac-mine) two)
while
((Y-rosetta fac-rosetta) 2)
works fine.
Where is the unguarded recursion happening?
I suspect it's something to do with how the if form works in clojure that's not completely equivalent to my is-zero implementation. But I haven't been able to find the error myself.
Thanks.
Update:
Taking into consideration #amalloy's answer, I changed fac-mine slightly to take lazy arguments. I'm not very familiar with clojure so, this is probably not the right way to do it. But, basically, I made is-zero take anonymous zero argument functions and evaluate whatever it returns.
(def lazy-one (fn [] one))
(defn lazy-next-term [n f]
(fn []
(multiply n (f (predecessor n)))))
(def fac-mine
(fn [f]
(fn [n]
((is-zero n
lazy-one
(lazy-next-term n f))))))
I now get an error saying:
=> ((Y-rosetta fac-mine) two)
ArityException Wrong number of args (1) passed to: core$lazy-next-term$fn clojure.lang.AFn.throwArity (AFn.java:437)
Which seems really strange considering that lazy-next-term is always called with n and f

The body of fac-mine looks wrong: it's calling (is-zero n one) for side effects, and then unconditionally calling (multiply n (f (predecessor n))). Presumably you wanted a conditional choice here (though I don't see why this doesn't throw an arity exception, given your definition of is-zero).

Related

fix-point combinators in clojure

One of my favorite ways to test the power of a language I'm learning is to try and implement various fixed-point combinators. Since I'm learning Clojure (though I'm not new to lisps), I did the same for it.
First, a little "testable" code, factorial:
(def !'
"un-fixed factorial function"
(fn [f]
(fn [n]
(if (zero? n)
1
(* n (f (dec n)))))))
(defn !
"factorial"
[n]
(if (zero? n)
1
(apply * (map inc (range n)))))
For any combinator c I implement, I want to verify that ((c !') n) is equal to (! n).
We start with the traditional Y:
(defn Y
"pure lazy Y combinator => stack overflow"
[f]
(let [A (fn [x] (f (x x)))]
(A A)))
But of course Clojure is not nearly so lazy as that, so we pivot to Z:
(defn Z
"strict fixed-point combinator"
[f]
(let [A (fn [x] (f (fn [v] ((x x) v))))]
(A A)))
And indeed, it holds that (= ((Z !') n) (! n)).
Now comes my issue: I cannot get either of U or the Turing combinator (theta-v) to work correctly. I suspect with U it's a language limit, while with theta-v I'm more inclined to believe it's a misread of Wikipedia's notation:
(defn U
"the U combinator => broken???"
[f]
(f f))
(defn theta-v
"Turing fixed-point combinator by-value"
[f]
(let [A (fn [x] (fn [y] (y (fn [z] ((x x) y) z))))]
(A A)))
A sample REPL experience:
((U !') 5)
;=> Execution error (ClassCastException) at fix/!'$fn (fix.clj:55).
;=> fix$_BANG__SINGLEQUOTE_$fn__180 cannot be cast to java.lang.Number
((theta-v !') 5)
;=> Execution error (ClassCastException) at fix/theta-v$A$fn (fix.clj:36).
;=> java.lang.Long cannot be cast to clojure.lang.IFn
Can anyone explain
Why these implementations of U and theta-v are not working; and
How to fix them?
Your definition of theta-v is wrong for two reasons. The first is pretty obvious: you accept f as a parameter and then ignore it. A more faithful translation would be to use def style, as you have for your other functions:
(def theta-v
"Turing fixed-point combinator by-value"
(let [A (fn [x] (fn [y] (y (fn [z] ((x x) y) z))))]
(A A)))
The second reason is a bit sneakier: you translated λz.xxyz to (fn [z] ((x x) y) z), remembering that lisps need more parentheses to denote function calls that are implicit in lambda-calculus notation. However, you missed one set: just as x x y z would have meant "evaluate x twice, then y once, then finally return z", what you wrote means "evaluate ((x x) y), then throw away that result and return z". Adding the extra set of parentheses yields a working theta-v:
(def theta-v
"Turing fixed-point combinator by-value"
(let [A (fn [x] (fn [y] (y (fn [z] (((x x) y) z)))))]
(A A)))
and we can demonstrate that it works by calculating some factorials:
user> (map (theta-v !') (range 10))
(1 1 2 6 24 120 720 5040 40320 362880)
As for U: to use the U combinator, functions being combined must change how they self-call, meaning you would need to rewrite !' as well:
(def U [f] (f f))
(def ! (U (fn [f]
(fn [n]
(if (zero? n)
1
(* n ((f f) (dec n))))))))
Note that I have changed (f (dec n)) to ((f f) (dec n)).

What are the limitations of forward declaring in Clojure? Why can't I use comp in this example?

I like my code to have a "top-down" structure, and that means I want to do exactly the opposite from what is natural in Clojure: functions being defined before they are used. This shouldn't be a problem, though, because I could theoretically declare all my functions first, and just go on and enjoy life. But it seems in practice declare cannot solve every single problem, and I would like to understand what is exactly the reason the following code does not work.
I have two functions, and I want to define a third by composing the two. The following three pieces of code accomplish this:
1
(defn f [x] (* x 3))
(defn g [x] (+ x 5))
(defn mycomp [x] (f (g x)))
(println (mycomp 10))
2
(defn f [x] (* x 3))
(defn g [x] (+ x 5))
(def mycomp (comp f g))
3
(declare f g)
(defn mycomp [x] (f (g x)))
(defn f [x] (* x 3))
(defn g [x] (+ x 5))
But what I would really like to write is
(declare f g)
(def mycomp (comp f g))
(defn f [x] (* x 3))
(defn g [x] (+ x 5))
And that gives me
Exception in thread "main" java.lang.IllegalStateException: Attempting to call unbound fn: #'user/g,
That would mean forward declaring works for many situations, but there are still some cases I can't just declare all my functions and write the code in any way and in whatever order I like. What is the reason for this error? What does forward declaring really allows me to do, and what are the situations I must have the function already defined, such as for using comp in this case? How can I tell when the definition is strictly necessary?
You can accomplish your goal if you take advantage of Clojure's (poorly documented) var behavior:
(declare f g)
(def mycomp (comp #'f #'g))
(defn f [x] (* x 3))
(defn g [x] (+ x 5))
(mycomp 10) => 45
Note that the syntax #'f is just shorthand (technically a "reader macro") that translates into (var f). So you could write this directly:
(def mycomp (comp (var f) (var g)))
and get the same result.
Please see this answer for a more detailed answer on the (mostly hidden) interaction between a Clojure symbol, such as f, and the (anonymous) Clojure var that the symbol points to, namely either #'f or (var f). The var, in turn, then points to a value (such as your function (fn [x] (* x 3)).
When you write an expression like (f 10), there is a 2-step indirection at work. First, the symbol f is "evaluated" to find the associated var, then the var is "evaluated" to find the associated function. Most Clojure users are not really aware that this 2-step process exists, and nearly all of the time we can pretend that there is a direct connection between the symbol f and the function value (fn [x] (* x 3)).
The specific reason your original code doesn't work is that
(declare f g)
creates 2 "empty" vars. Just as (def x) creates an association between the symbol x and an empty var, that is what your declare does. Thus, when the comp function tries to extract the values from f and g, there is nothing present: the vars exist but they are empty.
P.S.
There is an exception to the above. If you have a let form or similar, there is no var involved:
(let [x 5
y (* 2 x) ]
y)
;=> 10
In the let form, there is no var present. Instead, the compiler makes a direct connection between a symbol and its associated value; i.e. x => 5 and y => 10.
I think Alan's answer addresses your questions very well. Your third example works because you aren't passing the functions as arguments to mycomp. I'd reconsider trying to define things in "reverse" order because it works against the basic language design, requires more code, and might be harder for others to understand.
But... just for laughs and to demonstrate what's possible with Clojure macros, here's an alternative (worse) implementation of comp that works for your preferred syntax, without dealing directly in vars:
(defn- comp-fn-arity [variadic? args f & fs] ;; emits a ([x] (f (g x)) like form
(let [args-vec (if variadic?
(into (vec (butlast args)) ['& (last args)])
(apply vector args))
body (reduce #(list %2 %1)
(if variadic?
(apply list 'apply (last fs) args)
(apply list (last fs) args))
(reverse (cons f (butlast fs))))]
`(~args-vec ~body)))
(defmacro momp
([] identity)
([f] f)
([f & fs]
(let [num-arities 5
args-syms (repeatedly num-arities gensym)]
`(fn ~#(map #(apply comp-fn-arity (= % (dec num-arities)) (take % args-syms) f fs)
(range num-arities))))))
This will emit something kinda like comp's implementation:
(macroexpand '(momp f g))
=>
(fn*
([] (f (g)))
([G__1713] (f (g G__1713)))
([G__1713 G__1714] (f (g G__1713 G__1714)))
([G__1713 G__1714 G__1715] (f (g G__1713 G__1714 G__1715)))
([G__1713 G__1714 G__1715 & G__1716] (f (apply g G__1713 G__1714 G__1715 G__1716))))
This works because your (unbound) functions aren't being passed as values to another function; during compilation the macro expands "in place" as if you'd written the composing function by hand, as in your third example.
(declare f g)
(def mycomp (momp f g))
(defn f [x] (* x 3))
(defn g [x] (+ x 5))
(mycomp 10) ;; => 45
(apply (momp vec reverse list) (range 10)) ;; => [9 8 7 6 5 4 3 2 1 0]
This won't work in some other cases, e.g. ((momp - dec) 1) fails because dec gets inlined and doesn't have a 0-arg arity to match the macro's 0-arg arity. Again, this is just for the sake of example and I wouldn't recommend it.

Is there a simpler way to memoize a recursive let fn?

Let's say you have a recursive function defined in a let block:
(let [fib (fn fib [n]
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2)))))]
(fib 42))
This can be mechanically transformed to utilize memoize:
Wrap the fn form in a call to memoize.
Move the function name in as the 1st argument.
Pass the function into itself wherever it is called.
Rebind the function symbol to do the same using partial.
Transforming the above code leads to:
(let [fib (memoize
(fn [fib n]
(if (< n 2)
n
(+ (fib fib (- n 1))
(fib fib (- n 2))))))
fib (partial fib fib)]
(fib 42))
This works, but feels overly complicated. The question is: Is there a simpler way?
I take risks in answering since I am not a scholar but I don't think so. You pretty much did the standard thing which in fine is a partial application of memoization through a fixed point combinator.
You could try to fiddle with macros though (for simple cases it could be easy, syntax-quote would do name resolution for you and you could operate on that). I'll try once I get home.
edit: went back home and tried out stuff, this seems to be ok-ish for simple cases
(defmacro memoize-rec [form]
(let [[fn* fname params & body] form
params-with-fname (vec (cons fname params))]
`(let [f# (memoize (fn ~params-with-fname
(let [~fname (partial ~fname ~fname)] ~#body)))]
(partial f# f#))))
;; (clojure.pprint/pprint (macroexpand '(memoize-rec (fn f [x] (str (f x))))))
((memoize-rec (fn fib [n]
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2)))))) 75) ;; instant
((fn fib [n]
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2))))) 75) ;; slooooooow
simpler than what i thought!
I'm not sure this is "simpler" per se, but I thought I'd share an approach I took to re-implement letfn for a CPS transformer I wrote.
The key is to introduce the variables, but delay assigning them values until they are all in scope. Basically, what you would like to write is:
(let [f nil]
(set! f (memoize (fn []
<body-of-f>)))
(f))
Of course this doesn't work as is, because let bindings are immutable in Clojure. We can get around that, though, by using a reference type — for example, a promise:
(let [f (promise)]
(deliver! f (memoize (fn []
<body-of-f>)))
(#f))
But this still falls short, because we must replace every instance of f in <body-of-f> with (deref f). But we can solve this by introducing another function that invokes the function stored in the promise. So the entire solution might look like this:
(let [f* (promise)]
(letfn [(f []
(#f*))]
(deliver f* (memoize (fn []
<body-of-f>)))
(f)))
If you have a set of mutually-recursive functions:
(let [f* (promise)
g* (promise)]
(letfn [(f []
(#f*))
(g []
(#g*))]
(deliver f* (memoize (fn []
(g))))
(deliver g* (memoize (fn []
(f))))
(f)))
Obviously that's a lot of boiler-plate. But it's pretty trivial to construct a macro that gives you letfn-style syntax.
Yes, there is a simpler way.
It is not a functional transformation, but builds on the impurity allowed in clojure.
(defn fib [n]
(if (< n 2)
n
(+ (#'fib (- n 1))
(#'fib (- n 2)))))
(def fib (memoize fib))
First step defines fib in almost the normal way, but recursive calls are made using whatever the var fib contains. Then fib is redefined, becoming the memoized version of its old self.
I would suppose that clojure idiomatic way will be using recur
(def factorial
(fn [n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt))
;; Memoized recursive function, a mash-up of memoize and fn
(defmacro mrfn
"Returns an anonymous function like `fn` but recursive calls to the given `name` within
`body` use a memoized version of the function, potentially improving performance (see
`memoize`). Only simple argument symbols are supported, not varargs or destructing or
multiple arities. Memoized recursion requires explicit calls to `name` so the `body`
should not use recur to the top level."
[name args & body]
{:pre [(simple-symbol? name) (vector? args) (seq args) (every? simple-symbol? args)]}
(let [akey (if (= (count args) 1) (first args) args)]
;; name becomes extra arg to support recursive memoized calls
`(let [f# (fn [~name ~#args] ~#body)
mem# (atom {})]
(fn mr# [~#args]
(if-let [e# (find #mem# ~akey)]
(val e#)
(let [ret# (f# mr# ~#args)]
(swap! mem# assoc ~akey ret#)
ret#))))))
;; only change is fn to mrfn
(let [fib (mrfn fib [n]
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2)))))]
(fib 42))
Timings on my oldish Mac:
original, Elapsed time: 14089.417441 msecs
mrfn version, Elapsed time: 0.220748 msecs

Why is let not a valid recur target?

In clojure, this is valid:
(loop [a 5]
(if (= a 0)
"done"
(recur (dec a))))
However, this is not:
(let [a 5]
(if (= a 0)
"done"
(recur (dec a))))
So I'm wondering: why are loop and let separated, given the fact they both (at least conceptually) introduce lexical bindings? That is, why is loop a recur target while let is not?
EDIT: originally wrote "loop target" which I noticed is incorrect.
Consider the following example:
(defn pascal-step [v n]
(if (pos? n)
(let [l (concat v [0])
r (cons 0 v)]
(recur (map + l r) (dec n)))
v))
This function calculates n+mth line of pascal triangle by given mth line.
Now, imagine, that let is a recur target. In this case I won't be able to recursively call the pascal-step function itself from let binding using recur operator.
Now let's make this example a little bit more complex:
(defn pascal-line [n]
(loop [v [1]
i n]
(if (pos? i)
(let [l (concat v [0])
r (cons 0 v)]
(recur (map + l r) (dec i)))
v)))
Now we're calculating nth line of a pascal triangle. As you can see, I need both loop and let here.
This example is quite simple, so you may suggest removing let binding by using (concat v [0]) and (cons 0 v) directly, but I'm just showing you the concept. There may be a more complex examples where let inside a loop is unavoidable.

Why am I getting a cast error when trying to use Simpson's rule in Clojure?

I'm trying to work through some of the exercises in SICP using Clojure, but am getting an error with my current method of executing Simpson's rule (ex. 1-29). Does this have to do with lazy/eager evalution? Any ideas on how to fix this? Error and code are below:
java.lang.ClassCastException: user$simpson$h__1445 cannot be cast to java.lang.Number
at clojure.lang.Numbers.divide (Numbers.java:139)
Here is the code:
(defn simpson [f a b n]
(defn h [] (/ (- b a) n))
(defn simpson-term [k]
(defn y [] (f (+ a (* k h))))
(cond
(= k 0) y
(= k n) y
(even? k) (* 2 y)
:else (* 4 y)))
(* (/ h 3)
(sum simpson-term 0 inc n)))
You define h as a function of no arguments, and then try to use it as though it were a number. I'm also not sure what you're getting at with (sum simpson-term 0 inc n); I'll just assume that sum is some magic you got from SICP and that the arguments you're passing to it are right (I vaguely recall them defining a generic sum of some kind).
The other thing is, it's almost always a terrible idea to have a def or defn nested within a defn. You probably want either let (for something temporary or local) or another top-level defn.
Bearing in mind that I haven't written a simpson function for years, and haven't inspected this one for algorithmic correctness at all, here's a sketch that is closer to the "right shape" than yours:
(defn simpson [f a b n]
(let [h (/ (- b a) n)
simpson-term (fn [k]
(let [y (f (+ a (* k h)))]
(cond
(= k 0) y
(= k n) y
(even? k) (* 2 y)
:else (* 4 y))))]
(* (/ h 3)
(sum simpson-term 0 inc n))))