I'm a newcomer to J and I've been trying to create a Fibonacci function as an exercise (always the second function I create when learning a language). I just can't figure out what exactly is wrong in my way of doing it. I have tried to define it as tacit, but it gets hung if argument is greater than one.
fib =: [ ` (($: (]-1)) + ($: (]-2))) @. (>&1)
I've also attempted to create it explicitly, and that worked fine.
fib =: 3 : 'if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.'
I tried to create a tacit out of that by replacing 3 with 13, but it threw an error.
fib =: 13 : 'if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.'
|spelling error
| if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.
| ^
| fib=: 13 :'if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.'
So, I'm asking for someone to explain what exactly I am doing wrong here.
Here's an alternative that I think is both clearer and more concise:
Compare with a more canonical (pseudocode) definition:
First, instead of using
[ `with@. (>&1), which uses a gerund, it's better to use^:(1&<). Forf(n) if cond(n) else n, using the^:conjunction is more idiomatic;^:0means "do nothing" and^:1means "do once," so the intent is clear.@.is better suited to nontrivial behavior.Second, using the
&bond/compose conjunction simplifies the train significantly. Repeated uses of[:and]are rather confusing and opaque. Refactoring using&puts together related operations: first, splitninto two, namelyn-2andn-1, and second, add together thefibnof those two numbers.And, lastly,
"0for list handling andM.for memoizing.M.is rather important from a performance perspective, as a straightforward implementation of the canonical definition will callfib(2)excessively. You can have your cake (a simple definition) and eat it too (good performance) with the built-in memoization adverb.Source for this particular definition:
f0bon this page.