Creating a recursive tacit function in J
Asked Answered
H

2

6

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.

Havard answered 11/6, 2014 at 18:41 Comment(0)
L
4

Here's an alternative that I think is both clearer and more concise:

fibn =: (-&2 +&$: -&1)^:(1&<) M."0

Compare with a more canonical (pseudocode) definition:

fib(n) = fib(n-1) + fib(n-2) if n > 2 else n

First, instead of using [ ` with @. (>&1), which uses a gerund, it's better to use ^:(1&<). For f(n) if cond(n) else n, using the ^: conjunction is more idiomatic; ^:0 means "do nothing" and ^:1 means "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, split n into two, namely n-2 and n-1, and second, add together the fibn of those two numbers.

And, lastly, "0 for list handling and M. for memoizing. M. is rather important from a performance perspective, as a straightforward implementation of the canonical definition will call fib(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: f0b on this page.

Ly answered 13/8, 2014 at 13:20 Comment(3)
This is pretty much what I would do now. My answer shows how I found my solution, which I knew was wrong. Thank you for taking the time to write this anyways.Havard
No problem. I saw the timestamps, so I guessed you would probably have improved significantly and wouldn't personally need this advice, but I thought it'd be good to leave this for any newbies.Ly
I'll make this the accepted answer, as it does have some good information.Havard
H
4

Okay, I found it. I ran only the recursive block through tacit generator and got this block.

   13 : '(f y-1) + (f y-2)'
([: f 1 -~ ]) + [: f 2 -~ ]

Then I inserted that to the original piece, getting this.

fib =: [ ` (([: $: 1 -~ ]) + [: $: 2 -~ ]) @. (>&1)

And that works like a charm. I also inserted " 0 to the end to make it accept lists.

Havard answered 11/6, 2014 at 18:51 Comment(0)
L
4

Here's an alternative that I think is both clearer and more concise:

fibn =: (-&2 +&$: -&1)^:(1&<) M."0

Compare with a more canonical (pseudocode) definition:

fib(n) = fib(n-1) + fib(n-2) if n > 2 else n

First, instead of using [ ` with @. (>&1), which uses a gerund, it's better to use ^:(1&<). For f(n) if cond(n) else n, using the ^: conjunction is more idiomatic; ^:0 means "do nothing" and ^:1 means "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, split n into two, namely n-2 and n-1, and second, add together the fibn of those two numbers.

And, lastly, "0 for list handling and M. for memoizing. M. is rather important from a performance perspective, as a straightforward implementation of the canonical definition will call fib(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: f0b on this page.

Ly answered 13/8, 2014 at 13:20 Comment(3)
This is pretty much what I would do now. My answer shows how I found my solution, which I knew was wrong. Thank you for taking the time to write this anyways.Havard
No problem. I saw the timestamps, so I guessed you would probably have improved significantly and wouldn't personally need this advice, but I thought it'd be good to leave this for any newbies.Ly
I'll make this the accepted answer, as it does have some good information.Havard

© 2022 - 2024 — McMap. All rights reserved.