HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Clojure Fibonacci

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
clojurefibonaccistackoverflow

Problem

I'm a Clojure novice working through 4Clojure problems. In one problem I am supposed to create a function that takes a number and returns that number of Fibonaccis. My first thought was to create a function that creates a lazy sequence of Fibonaccis and then just takes however many it needs. Here is what I came up with:

(fn [numberOfFibs]
 (defn lazyFib [a b]
   (cons a (lazy-seq (lazyFib b (+ b a)))))
 (take numberOfFibs (lazyFib 1 1)))


This did work in my IDE but it wasn't accepted by 4Clojure due to the private defn. defs are not accepted by the website.

How can I refactor this function to remove the defn? And what are the problems with style and readability? Is it easy to reason about the function?

Solution

How can I refactor this function to remove the defn?

What you are looking for is letfn. It can be used to locally define a recursive function or corecursive functions. In this case:

(fn [numberOfFibs]
    (letfn [(lazyFib [a b] (cons a (lazy-seq (lazyFib b (+ b a)))))]
      (take numberOfFibs (lazyFib 1 1))))



And what are the problems with style and readability?

You shouldn't use nested defs. Behavior is not misleading. Especially it is not scoped in the form it appears and affects the current namespace, as if it was a top level form.

=> lazyFib
CompilerException java.lang.RuntimeException: Unable to resolve symbol: lazyFib in this context, compiling:(NO_SOURCE_PATH:1:42) 
=> (fn [numberOfFibs]
    (defn lazyFib [a b]
      (cons a (lazy-seq (lazyFib b (+ b a)))))
    (take numberOfFibs (lazyFib 1 1)))
#
=> lazyFib
#
=> ((fn [numberOfFibs]
    (defn lazyFib [a b]
      (cons a (lazy-seq (lazyFib b (+ b a)))))
    (take numberOfFibs (lazyFib 1 1))) 10)
(1 1 2 3 5 8 13 21 34 55)
=> lazyFib
#


Especially confusing is that just evaluating the fn without calling it pollutes the namespace with an unbound name.


Is it easy to reason about the function?

Other than the nested defn it is very understandable.

Code Snippets

(fn [numberOfFibs]
    (letfn [(lazyFib [a b] (cons a (lazy-seq (lazyFib b (+ b a)))))]
      (take numberOfFibs (lazyFib 1 1))))
=> lazyFib
CompilerException java.lang.RuntimeException: Unable to resolve symbol: lazyFib in this context, compiling:(NO_SOURCE_PATH:1:42) 
=> (fn [numberOfFibs]
    (defn lazyFib [a b]
      (cons a (lazy-seq (lazyFib b (+ b a)))))
    (take numberOfFibs (lazyFib 1 1)))
#<resistors$eval4432$fn__4433 deneme.resistors$eval4432$fn__4433@49531c8c>
=> lazyFib
#<Unbound Unbound: #'deneme.resistors/lazyFib>
=> ((fn [numberOfFibs]
    (defn lazyFib [a b]
      (cons a (lazy-seq (lazyFib b (+ b a)))))
    (take numberOfFibs (lazyFib 1 1))) 10)
(1 1 2 3 5 8 13 21 34 55)
=> lazyFib
#<resistors$eval4440$fn__4441$lazyFib__4442 deneme.resistors$eval4440$fn__4441$lazyFib__4442@6d17b6ce>

Context

StackExchange Code Review Q#73827, answer score: 5

Revisions (0)

No revisions yet.