I'm still learning F#, so please be gentle with me! I tried to define a function to generate Fibonacci numbers like this...
let rec fib n =
match n with
| 0 -> 1
| 1 -> 1
| n -> fib(n-1) + (fib n-2)
However, whilst this gives the correct result for 0 and 1, it gives a stack overflow for 2. I know this isn't tail recursive, but for an input of 2, I wouldn't expect that to be an issue.
I thought pattern matching worked its way down, so with an input of 2, it would match the third pattern, giving a result of 1+1 (being the results of fib 0 and fib 1).
Why am I getting the SO?
You statement:
| n -> fib(n-1) + (fib n-2)
Means:
| n -> fib(n-1) + fib(n)-2
If i have a call like this, it would work well with fib(n-1) since with each call value of n would be decremented by 1 while for fib(n) you would keep on calling the same method with same value until you get stackoverflow exception. To avoid this, you need:
| n -> fib(n-1) + fib(n-2)
Related
I currently have this f# function
let collatz' n =
match n with
| n when n <= 0 -> failwith "collatz' :n is zero or less"
| n when even n = true -> n / 2
| n when even n = false -> 3 * n + 1
Any tips for solving the following problem in F#?
As said in the comments, you need to give a bit more information for any really specific advice, but based on what you have I'll add the following.
The function you have declared satisfies the definition of the Collatz function i.e. even numbers -> n/2 ,and
odd number -> 3n + 1.
So really you only need applyN, let's break it down into its pieces
( `a -> `a) -> `a -> int -> `a list
applyN f n N
That definition is showing you exactly what the function expects.
lets look at f through to N
f -> a function that takes some value of type 'a (in your case likely int) and produces a new value of type 'a.
This corresponds to the function you have already written collatz`
n -> is your seed value. I don't think elaboration is required.
N -> This looks like a maximum amount of steps to go through. In the example posted, if N was larger, you would see a loop [ 1 ;4; 2; 1; 4... ]
and if it was smaller it would stop sooner.
So that is what the function takes and need to do, so how can we achieve this?
I would suggest making use of scan.
The scan function is much like fold, but it returns each interim state in a list.
Another option would be making use of Seq.unfold and then only taking the first few values.
Now, I could continue and give some source code, but I think you should try yourself for now.
I have been trying to write a recursive function which takes a certain number as an input and outputs the sum of all the numbers that are multiples of 3 and 5 from 1 to the input number (3 + 5 + 9..n).
Here is my code
let rec add_nums n =
if n < 1 then 0
if (n%5 > 0) then 0
else n + add_nums(n-1)
if's are expressions in F# rather than statements. Since they're expressions, both then and else branches need to have the same return type. What this means in practice is that you cannot have an if without an else branch unless then branch returns a unit (which allows the else branch to be omitted). The compiler sees that else was omitted, and infers that the type of then branch should have been unit.
This fixes it:
let rec add_nums n =
if n < 1
then 0
else if (n%5 > 0)
then 0
else n + add_nums(n-1)
If you format your if's that way, it will make catching such problems easier.
And arguably you could also put both your predicates in a single if.
May I boldly suggest using a match?
let rec add_nums n =
match n with
| x when x < 1 -> 0
| x when x % 5 > 0 -> 0
| _ -> n + add_nums(n-1)
Adding more conditions then is somewhat "easier" and (can be) more readable...
Using match is also "better" in the regard that it will (possibly) make it easier to see errors in return value.
I've been trying to understand continuations / CPS and from what I can gather it builds up a delayed computation, once we get to the end of the list we invoke the final computation.
What I don't understand is why CPS prevents stackoverflow when it seems analogous to building up a nested function as per the naive approach in Example 1. Sorry for the long post but tried to show the idea (and possibly where it goes wrong) from basics:
So:
let list1 = [1;2;3]
Example 1: "Naive approach"
let rec sumList = function
|[] -> 0
|h::t -> h + sumList t
So when this runs, iteratively it results in:
1 + sumList [2;3]
1 + (2 + sumList [3])
1 + (2 + (3 + 0))
So the nesting (and overflow issues) can be overcome by Tail Recursion - running an accumulator i.e.
"Example 2: Tail Recursion"
let sumListACC lst =
let rec loop l acc =
match l with
|[] -> acc
|h::t -> loop t (h + acc)
loop lst 0
i.e,
sumList[2;3] (1+0)
sumList[3] (2+1)
sumList[] (3+3)
So because the accumulator is evaluated at each step, there is no nesting and we avoid bursting the stack. Clear!
Next comes CPS, I understand this is required when we already have an accumulator but the function is not tail recursive e.g. with Foldback. Although not required in the above example, applying CPS to this problem gives:
"Example 3: CPS"
let sumListCPS lst =
let rec loop l cont =
match l with
|[] -> cont 0
|h::t -> loop t (fun x -> cont( h + x))
loop lst (fun x -> x)
To my understanding, iteratively this could be written as:
loop[2;3] (fun x -> cont (1+x))
loop[3] (fun x ->cont (1+x) -> cont(2+x))
loop[] (fun x -> cont (1+x) -> cont(2+x) -> cont (3+x)
which then reduces sequentially from the right with the final x = 0 i.e:
cont(1+x)-> cont(2+x) -> cont (3+0)
cont(1+x)-> cont(2+x) -> 3
cont(1+x) -> cont (2+3)
...
cont (1+5) -> 6
which I suppose is analogous to:
cont(1+cont(2+cont(3+0)))
(1+(2+(3+0)))
correction to original post - realised that it is evaluated from the right, as for example replacing cont(h +x) with cont(h+2*x) yields 17 for the above example consistent with: (1+2*(2+2*(3+2*0)))
i.e. exactly where we started in example 1, based on this since we still need to keep track of where we came from why does using it prevent the overflow issue that example 1 suffers from?
As I know it doesn't, where have I gone wrong?
I've read the following posts (multiple times) but the above confusion remains.
http://www.markhneedham.com/blog/2009/06/22/f-continuation-passing-style/
http://codebetter.com/matthewpodwysocki/2008/08/13/recursing-on-recursion-continuation-passing/
http://lorgonblog.wordpress.com/2008/04/05/catamorphisms-part-one/
What happens is quite simple.
.NET (and other platforms, but we're discussing F# right now) stores information in two locations: the stack (for value types, for pointer to objects, and for keeping track of function calls) and the heap (for objects).
In regular non-tail recursion, you keep track of your progress in the stack (quite obviously). In CPS, you keep track of your progress in lambda functions (which are on the heap!), and tail recursion optimization makes sure that the stack stays clear of any tracking.
As the heap is significantly larger than the stack, it is (in some cases) better to move the tracking from the stack to the heap - via CPS.
I'm trying to create a list and print it out, counting down from N to 1. This is my attempt:
%% Create a list counting down from N to 1 %%
-module(list).
-export([create_list/1]).
create_list(N) when length(N)<hd(N) ->
lists:append([N],lists:last([N])-1),
create_list(lists:last([N])-1);
create_list(N) ->
N.
This works when N is 1, but otherwise I get this error:
172> list:create_list([2]).
** exception error: an error occurred when evaluating an arithmetic expression
in function list:create_list/1 (list.erl, line 6)
Any help would be appreciated.
You should generally avoid using append or ++, which is the same thing, when building lists. They both add elements to the end of a list which entails making a copy of the list every time. Sometimes it is practical but it is always faster to work at the front of the list.
It is a bit unclear in which order you wanted the list so here are two alternatives:
create_up(N) when N>=1 -> create_up(1, N). %Create the list
create_up(N, N) -> [N];
create_up(I, N) ->
[I|create_up(I+1, N)].
create_down(N) when N>1 -> %Add guard test for safety
[N|create_down(N-1)];
create_down(1) -> [1].
Neither of these are tail-recursive. While tail-recursion is nice it doesn't always give as much as you would think, especially when you need to call a reverse to get the list in the right order. See Erlang myths for more information.
The error is lists:last([N])-1. Since N is an array as your input, lists:last([N]) will return N itself. Not a number you expect. And if you see the warning when compiling your code, there is another bug: lists:append will not append the element into N itself, but in the return value. In functional programming, the value of a variable cannot be changed.
Here's my implementation:
create_list(N) ->
create_list_iter(N, []).
create_list_iter(N, Acc) ->
case N > 0 of
true -> NewAcc = lists:append(Acc, [N]),
create_list_iter(N-1, NewAcc);
false -> Acc
end.
If I correctly understand your question, here is what you'll need
create_list(N) when N > 0 ->
create_list(N, []).
create_list(1, Acc) ->
lists:reverse([1 | Acc]);
create_list(N, Acc) ->
create_list(N - 1, [N | Acc]).
If you work with lists, I'd suggest you to use tail recursion and lists construction syntax.
Also, to simplify your code - try to use pattern matching in function declarations, instead of case expressions
P.S.
The other, perhaps, most simple solution is:
create_list(N) when N > 0 ->
lists:reverse(lists:seq(1,N)).
As per the MSDN documentation, while writing recursive function, The use of the accumulator argument makes the function tail recursive, which saves stack space.
I'm using two example given on the MSDN site to calculate of sum of all the numbers in a list-
first without tail recursion-
let rec Sum myList =
match myList with
| [] -> 0
| h::t -> h + Sum t
and now with tail recursion-
let Sumtail list =
let rec loop list acc =
match list with
| h::t -> loop t acc + h
| [] -> acc
loop list 0
and running both the functions with input [1..100000].
Function Sum successfully calculates the sum of this list but gives stackoverflow exception if I pass [1..1000000]
but the second function Sumtail fails at [1..100000] while it should give better performance then the first function since it uses tail recursion.
Are there any other factors which affects the recursive function?
Your second function isn't tail-recursive since loop t acc + h is parsed as (loop t acc) + h which makes + become the last operation on loop.
Change loop t acc + h to loop t (acc + h) in order that the function becomes tail-recursive.