views:

382

answers:

9

Consider the following (Haskell) code:

fib=0:1:zipWith (+) fib (tail fib)

A coworker is trying to assert that this is not a recursive function because fib is simply a list that defines itself with itself and that is somehow different than a function that does the same. I think he's smoking crack.

What do you think?

+3  A: 

He's on crack - the above function is clearly recursive.

pirhac
The above is clearly recursive, but it is not a function.
sepp2k
sepp2k: `zipWith` is a function.
Piet Delport
@Piet: The question was whether `fib` was a recursive function, not whether `zipWith` was.
sepp2k
sepp2k: The question was whether "the following code" was a recursive function, and it clearly is. The fact that `fib` only refers to the result of the recursive function is besides the point, and does not change the fact that the body is a recursive function.
Piet Delport
+3  A: 

The example you've given is recursive. But the Fibonacci sequence by nature doesn't have to be. There are iterative versions of the algorithm, and even explicit functions.

Evan Carroll
Iteration is just a special case of recursion, and generating a sequence will always be recursive in some sense, for hopefully obvious reasons. The formula to compute single terms independently, however, is not itself recursive (although it uses functions that will probably be calculated recursively).
camccann
+10  A: 

The fibonacci definition with zipWith is not a recursive function, in fact there is no function involved, fib is a list (data) that is lazily self-defined, utilizing Haskell's lazy semantic. In a sense, you can call it recursive list or recursive data; but not recursive function.

It may be difficult to wrap your head around recursive list since very little programming languages have anything close, but you'll notice that in Haskell all functions takes exactly one paramater. fib does not take any parameter, because it's not a function. Since there is no function involved, you can't have recursive function.

Your coworker isn't smoking crack, he's enlightened (or smoking crack, if that's your definition of enlightenment).

Lie Ryan
This is simply wrong: `zipWith` is a recursive function defining the sequence. `fib` is not a recursive list: it is a plain, non-recursive list referring to the *result of evaluating the recursive function `zipWith`*. (Yes, Haskell also supports recursive data, but this refers to definitions like `xs = 1:2:3:xs`, not to question's example.)
Piet Delport
@Piet Delport: `fib` appears on the right hand side of its own definition.... what word do you use for that? I call that "recursive". Neither the recursiveness nor functionalness (functionality?) of `zipWith` is being called into question here.
pelotom
pelotom: In Haskell, there is a fundamental difference between recursive *data* and recursive *functions*. Recursive data is when a data structure concretely refers back to its own constructors, as happens when you say `xs = 1:2:3:xs`: the final cons refers back to the initial one, forming a cycle. There are many different ways to achieve this kind of data recursion: see [Tying the Knot](http://www.haskell.org/haskellwiki/Tying_the_Knot). Recursive functions, on the other hand, are like `zipWith`. They may or may not define recursive data structures, too, but in this case, `fib` is not.
Piet Delport
@Piet: `xs = 1:2:3:xs` is a self-referential definition, as is `fib=0:1:zipWith (+) fib (tail fib)`. they're both recursive data. What's the problem?
pelotom
pelotom: No, `xs` is recursive data without any function, `fib` is *non-recursive* data generated by a recursive function.
Piet Delport
@Piet: the fact that `fib` makes use of `zipWith` in its definition is neither here nor there. `fib` is most certainly recursive data, as attested to by the fact that it is *defined in terms of itself*. See those 2 instances of `fib` on the RHS of the equation? That means it's defined in terms of itself, e.g. it is recursive. I don't know how many different ways I can restate this basic point.
pelotom
pelotom: The `zipWith` *function* is defined in terms of itself. The recursion never escapes to become part of the list structure: if it did, the list would repeat (and it's obvious that Fibonacci sequence does not repeat). Rather than continue a pointless argument of definitions, i would recommend reading more about the topic of circular and self-referential data structures in Haskell: it's rich and rewarding beyond just this question.
Piet Delport
*"The recursion never escapes to become part of the list structure: if it did, the list would repeat (and it's obvious that Fibonacci sequence does not repeat)"* Uh, what? Since when does recursion imply repetition?
pelotom
pelotom: Recursive *data* (e.g. `xs = 1:2:3:xs`) is data that refers to itself, implying *data-level* repetition. Recursive *functions* (e.g. `zipWith`) are functions that refer to themselves, implying *function-level* repetition. (Recursive *types* are types that refer to themselves, implying *type-level* repetition... you get the idea.) Each of these examples of recursion (data, function, type) are completely distinct and orthogonal, and each of them implies repetition / self-reference / recurrence at their own respective level of abstraction, independent of the others.
Piet Delport
@Piet Delport: Recursive data is data that is defined with reference to itself; a recursive data has the general form of: `recd = a1 : a2 : ... : an : (f recd)`. The case of `xs = 1 : 2 : 3 : xs` is only a special case when `f x = x`. Therefore `fib` is a recursive data when `f x = zipWith (+) x (tail x)`. That `f` internally uses a recursive function (e.g. `zipWith`) is totally irrelevant.
Lie Ryan
+2  A: 

Aside from the Haskell implementation here, the Fibonacci Numbers are a sequence defined by a recurrence relation. Mathematically speaking, each term is defined as a function of the preceding terms. Defeat him with mathematical semantics.

Andy
Although the standard definition is the recurrence relation, any given implementation could use the closed form (even though this one doesn't), so this wouldn't be a sound argument for implementation questions.
John
+5  A: 

It's recursive. You can tell because the name on the LHS of the = also appears on the RHS.

It is however not a function. You can tell because the type of fib does not contain a ->.

sepp2k
It’s been a long time since I’ve last used Haskell. Is using the function constructor a hard requirement to make a function? I can’t find a definite statement in the Haskell report but the function type is lexically defined as `type ::= btype [-> type]`, i.e. the function constructor followed by another type is optional. However, later it says that “A function type has the form `t1 -> t2` …”. [[source](http://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-620004)]
Konrad Rudolph
`fib` is not the function, `zipWith` is.
Piet Delport
@Piet: But that was not the question. The OP specifically says "this Fibonacci sequence function", so he's clearly not asking about zipWith (unless you're saying zipWith is "Fibonacci sequence function").
sepp2k
sepp2k: Yes, that is what's confusing people. In Haskell terms, `zipWith (+) fib (tail fib)` is the Fibonacci sequence function in the above code. `fib`, in this case, is merely a reference to the (non-recursive) list being *generated* by the aforementioned recursive function.
Piet Delport
@Piet: But `zipWith (+) fib (tail fib)` is also not a function. `zipWith` is a function, `zipWith (+) fib (tail fib)` is the result of applying that function.
sepp2k
sepp2k: No, `zipWith (+) fib (tail fib)` is a *function application*, and it does not become a result until evaluated. (This may seem like nit-picking, but it's a very deep and important distinction at the very heart of Haskell: a function application may always result in ⊥, and the whole point of non-strict evaluation in Haskell is to allow such ⊥-valued function applications, without evaluating them to their (fatal) result unless strictly necessary.)
Piet Delport
@Piet: Well, fine, but a function application is still not the same as a function.
sepp2k
sepp2k: Right. (But that's besides the point of the question being a recursive function definition of the Fibonacci sequence.)
Piet Delport
@Piet: No, it's not besides the point at all. As you said yourself, the question was whether a recursive function is being defined here. Since the only thing being defined here is `fib` and `fib` is not a function, the answer to that is clearly no.
sepp2k
sepp2k: Now you're just being obtuse: there is no `fib` without the recursive function that is its body. (And no one asked whether `fib` was a function: the question was whether "the function [is] recursive", and `zipWith` is the only function there.)
Piet Delport
There is definitely somebody being obtuse here.
pelotom
+2  A: 

For this to be recursive function, it needs to be both recursive and a function. As sepp2k points out, it's clearly recursive because the name fib appears on both sides of the =. That is, fib is defined in terms of itself.

Is it a function? Not according to its type. In haskell, we call a 0-argument function "data". So this definition of fib creates a recursive data structure, but not a recursive function.

John
`fib` is a *not* a recursive data structure in this case: "recursive data structure" means something entirely different in Haskell. `fib` is an infinite, non-repeating (and hence non-recursive) data structure generated by a recursive function (`zipWith`).
Piet Delport
+5  A: 

My, what a rat's nest of subtle terminological distinctions. What is "this"?

fib=0:1:zipWith (+) fib (tail fib)

It is not a recursive function. It is not recursive data. It is a recursive definition.

What is being defined?

fib

What type of thing is fib, according to this definition?

[Integer]

A list of integers (or perhaps a list of any old numeric stuff).

Is fib a function? No, it is a list. Is fib recursively defined? Yes. Would fib be recursively defined if we replaced zipWith by a nonrecursive function of the same type (e.g. \ f xs ys -> xs)? Yes, although it would be a different recursively defined list.

Is fib a cyclic list? No. Does "recursive data structure" mean "cyclic data structure"? Not according to Hoare's paper, "Recursive Data Structures": http://portal.acm.org/book_gateway.cfm?id=63445&type=pdf&bookpath=%2F70000%2F63445%2Fcb-p217-hoare.pdf&coll=&dl=&CFID=15151515&CFTOKEN=6184618

In a typed setting, "recursive data structure" means no more or less than "inhabitant of a recursively defined type". Correspondingly "fred" is a recursive data structure, even though it is not recursively defined, and indeed it can be acted upon by recursive functions such as ++.

The phrase "recursive function" means "recursively defined function". The phrase "recursive value" means "recursively defined value", such as exist in nonstrict languages: strict languages have the "value recursion" problem.

And if you think that's pedantic, try defining fib that way in a total programming language, and you'll discover that the notion of "recursive definition" splits into "definition by structural recursion" (consuming data in a way which stops) and "definition by guarded corecursion" (producing data in a way which goes), and that fib is of the latter variety. In that setting, the productivity of fib depends crucially on the laziness of zipWith. In the Haskell setting, of course, you don't need to worry about any of that stuff to figure out what sort of definition something is, just to figure out whether it has half a chance of actually working.

Conor McBride
+1  A: 

Since most answers support your coworker with respect to the function part of: "fib is not a recursive function." I'd like to elaborate on on the recursive part Conor McBride hinted at in his answer.

The definition given for fib is not recursive, it is co-recursive.

Co-recursion looks a lot like recursion in that, as many posters have pointed out, the LHS of the definition appears on the RHS too. But there is no base case. Recursion and corecursion "run in opposite directions".

The above definition of fib starts from the initial values 0 and 1 and moves "up" from there and keeps on going. On the other hand a recursive definition of, say (a function calculating) the n-th Fibonacci number

fib' 0 = 0
fib' 1 = 1
fib' n = fib' (n-1) + fib' (n-2)

walks "downwards" from the n-th number until it reaches the base cases and there stops.

I guess this vindicates the crackhead in both points :-)


For further reading check out the wikipedia article on Corecursion and the links there. If you can get you hands on it, Chapter 10 of The Haskell Road to Logic, Maths and Programming by Kees Doets and Jan van Eijck may be worth a peek.

jvk
A: 

Although many people in the comments are arguing whether or not the definition is a function, but everyone seems to agree that it is recursive.

As for the function/nonfunction argument, in Haskell, from the programmer's point of view, IT DOESN'T MATTER! Because both functions and data structures are evaluated lazily, a value and a function of no arguments returning a value are indistinguishable. What you have is a list of integers, evaluated lazily and recursively. fib is simultaneously a "list of integers", a "function of no arguments returning a list of integers", a "list of functions of no arguments returning integers", and "a function of no arguments returning a list of functions of no arguments returning integers".

It honestly does not matter. The language makes no distinction between the four. Type theory makes no distinction between the four (and countless others: a function of no arguments returning any of those is equally valid, as is a function of no arguments returning that, ad infinitum). It honestly makes no difference whether or not you call fib a "function" or not.

But it is recursive.

sxeraverx