Hi, Simon.
I see at least two ways to generate Fib numbers efficiently. Here is the code.
We need helper function.
let AddAndSwap(one, two) = (two, one + two)
And then use sequence to yield all numbers sequentially up until given number
let fibs n = seq {
if n >= 0 then yield 1
if n >= 1 then yield 1
if n >= 2 then
let pair = ref (1,1)
for i = 2 to n do
pair := AddAndSwap !pair
yield snd (!pair)
}
[0..5] |> List.map (fibs >> List.of_seq)
>
val it : int list list =
[[1]; [1; 1]; [1; 1; 2]; [1; 1; 2; 3]; [1; 1; 2; 3; 5]; [1; 1; 2; 3; 5; 8]]
Or you can use memoization technique, below is a sample from Expert F#
//generic memoize function from Expert F# book
let memoize (f: 'a -> 'b) =
let t = new System.Collections.Generic.Dictionary<'a,'b>()
fun n ->
if t.ContainsKey(n) then t.[n]
else let res = f n
t.Add(n,res)
res
let rec fibFast =
memoize (fun n -> if n < 2 then 1 else fibFast(n-1) + fibFast(n-2))
[0..5] |> List.map (fibFast)
>
val it : int list = [1; 1; 2; 3; 5; 8]
regards,
Alex
if you want to generate sequences, I think this is a better implementation:
1 2
let fibs = (1I, 1I) |> Seq.unfold(fun (n0, n1) -> Some(n0, (n1, n0 + n1)))
Also, you can use LazyList:
1 2
let fibs = (1I, 1I) |> LazyList.unfold(fun (n0, n1) -> Some(n0, (n1, n0 + n1)))
Ideally, to memoize a recursive function, you should use the y combinator [link:matt.might.net]
Two things. First, your original three-line lazyFunc/test1/test2 example computes two different lazy values and then 'forces' the values on the test1 and test2 lines (that's what calling .Value does). It seems like you have some different expectation? I'm not sure what it might be, though; clearly in order for test1 to have the final value '1' and test2 to have the final value '4' we have to run the body of the lazyFunc function two different times with different argument values.
Second, in terms of the big picture and terminology, it's not laziness that would make the recursive 'fib' example efficient, rather it's memoization. The F# lazy type does memoize, specifically in your second three-line example, test1 will 'force' the value stored in 'lazyFunc' (and print the message), and thus when test2 re-forces the value, it can just return the cached/memoized result (since it refers to the same 'lazyFunc' object, which already has been evaluated).
A memoized efficient implementation of 'fib' (in any language) requires storing some kind of dictionary so that, e.g. once you compute that (fib 4)=5, you store the key-value-pair (4,5) so that the next time you ask for (fib 4) again it can return the same (already computed) Lazy<int> object (that already knows that the answer is 5).
Memoization makes sense. After I posted I thought maybe Haskell had some sort of reduction optimization that reduced ``fib A'' everywhere to the same computation. But, it looks like it works the same way in Haskell as F# (provided the Haskell thunk is actually evaluated): [link:www.haskell.org]
I don't think lazy functions with arguments make sense. In your lazyFunc example, I would not expect x=1 and x=2 to return the same result (lazy or eager).
For the fib function, what does laziness buy you? ``fib n'' should always evaluate until ``fib 0''. I might expect a lazy implementation to be less efficient.
Thanks for your answer!
Sorry, in the lazyFunc example is a typo. The parameter x should be the same in both cases. So it should look like this:
let test1 = (lazyFunk 1).Value
let test2 = (lazyFunk 1).Value
But the output remains the same.
So what does laziness buy me? I will explain this with a little example. Say we want to compute 5th number of the fibonacci sequence. This would lead to the following computations
Even in this simple example occurs a lot of recurrent computation (e.g. fib(1) is evaluated 4 times). Built that tree for fib(10000) and you will know, why this is inefficient. With lazy evaluation this problem wouldn't occur. Lazy evaluation means compute only if needed and only once.
In our example this means that fib(1) will be evaluated once and the result will be cached. Any further calls to fib(1) doesn't result in reevaluation of fib(1), but in an access to a cache where the result is stored.
The result would be a huge performance boost for this algorithm.
Of course there is an easy solution to this problem. You could just build a cache manually. But then I can go ahead and code the whole thing in C# as easily than in F#.
In my opinion lazy evaluation is one of the most important benefits of functional programming languages compared to imperative ones. So it would be sad if the support of lazy evaluation in F# is quite limited.
Lazy evaluation means compute only if needed and only once.
Agreed.
In our example this means that fib(1) will be evaluated once and the result will be cached. Any further calls to fib(1) doesn't result in reevaluation of fib(1), but in an access to a cache where the result is stored.
You are still labelling this 'lazy evaluation' but the rest of us are calling this portion 'memoization', and it is distinct from lazy evaluation. In any language with arbitrary effects that cannot be reasoned about in the type system (such as, say, F#), memoization must be explicitly authored by the user (lest the compiler silently 'optimize away' an effect you authored and intended).
It's a limitation, but it's also a feature. As someone else has pointed out, you can writ e a generic 'memoize' function and use it to write the 'fast' version of fib.
As I started this post, I thought the term "lazy evaluation" would be quite definite.
However, this discussion shows my understanding of "lazy evaluation" differs from
what other people in this thread think about this term. So I gonna explain my point
of view which is based on the definition of lazy evaluation given in the book "Introduction
to functional programming using Haskell" by Richard Bird, Thomas E. Scruggs,
und Margo A. Mastropieri von Prentice Hall. Here's
a Link to the book at Amazon.com.
First of all, let's consider the evaluation of a simple expression as the following:
1 2
let square x = x * x let result = square (3+7)
If we want to evaluate the expression "square (3+7)" there are two policies to do
that. The first is called innermost reduction and the second is called outermost
reduction. With innermost reduction you reduce an innermost redex
in each step. Well, what's an innermost redex? Let's have look what the book says
about that.
"The word 'redex' is short for 'reducable expression', and an innermost redex is
one that contains no other redex." Okay, that's an innermost redex. An outermost
redex is just the opposite. Once again a definition from the book. "An outermost
redex is one that is contained in no other redex." At first this might be a bit
confusing, but I think looking at our example this comes into sharper relief.
In the expression "square(3+7)" the section "3+7" is an innermost redex, because
the numbers 3 and 7 are literals, so that "3+7" contains no other redex anymore.
However, the function square(...) is an outermost redex, as there is no other redex
containing square. Now that we know the difference between innermost and outermost
reduction, let's take a look at the reduction sequences of "square (3+7)" using
the different policies (see Example 1).
Example 1
As you noticed for sure innermost
reduction needs one step less than outermost reduction. As you can imagine the reduction
of more complex expressions leads to a significantly larger difference. Fortunately
there has been a number of smart people, which had an idea to fix this problem.
The solution is called graph reduction. With graph reduction subexpressions
can be shared, so that almost no repeated computation occurs anymore. This is achieved
by replacing every occurence of a subexpression with a pointer, pointing to one
instance of this subexpression. Look at the next example using outermost graph reduction
to get a grasp of this approach (Example 2).
Example 2
So here's another extract from the book: "With graph reduction, outermost reduction
never takes more steps than innermost reduction. Henceforth we will refer to outermost
graph reduction by its common name, lazy evaluation and to innermost graph
reduction as eager evaluation."
Sounds interesting, but why is outermost graph reduction also called lazy evaluation?
The next example will give us a better understanding.
Consider the following:
1 2
let fst a b = a let result = fst (square(3+7)) (square(2+5))
What fst simply does is that it takes two arguments and returns the first one. Take
a look at the reduction sequence (Example 3).
Example 3
As you notice with lazy evaluation we save a lot of work, as the function fst doesn't
need the second argument. So let's sum up the advantages of lazy evaluation by taking
another look into our book.
"We will adopt lazy evaluation as our model of computation, because it has to desirable
properties: (i) it terminates whenever any reduction order terminates, and (ii)
it requires no more (and possible fewer) steps than eager evaluation.
With this definition of lazy evaluation in hand, let's go back to our original problem:
Computing fibs with lazy evaluation. As you notice in the following reduction sequence
(Example 4), there doesn't occur any reevaluation, although I haven't declared any
memoization manually.
Example 4
As I'm not a Haskell expert, I have to admit, that I'm not absolutely sure that
Haskell actually reduces the sequence in the way I did. So any comments regarding
this reduction sequence are highly appreciated.
If you need some additional information about lazy evaluation, take a look here.
So I hope that someone has made it up here;)
Here are my questions regarding F#:
(i) Does F# supports lazy evaluation in a similar way, or is it possible to achieve
a similar behaviour with some workarounds?
and (ii) Is there a way to produce a lazy function in F# that has arguments?
@none: Thanks for the hint to y combinator. Sounds really interesting. I'll
have a look the next few days.
@avsbox: Thanks for the efficient implementations. Seems like this is the
way to go in F#. But actually I'm testing how much lazy evaluation regarding the
definition above, F# offers.
(i) Does F# supports lazy evaluation in a similar way, or is it possible to achieve a similar behaviour with some workarounds?
No. The picture in example 4 auotmagically seems to discover that both (fib 1) calls are a 'common subexpression' that can be shared. I don't know if any real languages (Haskell included) do this; F# certainly does not, because as I mentioned before, it has no way that the call does not contain an intended side-effect (in which case only evaluating the function once would be an error, since the program explicitly asked to evaluate it twice).
The stuff in the book here all looks like a pipe dream to me, for people discussing 'modes of computation' rather than 'programming with computers in the real world', but perhaps I am too jaded. :)
Thanks for your estimation. I think I'm going to post the last reduction sequence to a Haskell forum. There might be a Haskell Guru, who is able to estimate wether this reduction sequence is reality or just a 'pipe dream':)
As soon as I' ve got an answer, I will post it here.
1 Naive definition
The standard definition can be expressed directly:
1 2 3fib 0 = 0 fib 1 = 1 fib n = fib (n-1)+ fib (n-2)
This implementation requires O(fib n) additions.
So, no, Haskell doesn't appear to memoize those subexpressions.
I think in your example, you get 2 lazy variables. (and in the fibonacci graph, you get n lazy values).
Consider this example:
1 2 3 4 5 6
let lazyFunkOne = lazyFunk 1 let test1 = lazyFunkOne .Value let test2 = lazyFunkOne .Value
You really want memoization. So, that the first call to fib evaluates, and subsequent calls use the lookup.
I don't know of a compiler that will reduce every occurrence of, say, (lazyFunk 1) to be _the same_ lazy value. When you look at the simple case, it seems obvious that the compiler ``should'' reduce them. But, the general case gets very complex (even for the simple fib function). Memoization [link:en.wikipedia.org] is the way to avoid unnecessary reevaluation in functional languages.
What language implements laziness in the way that you describe?
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
Hallo Everyone,
for the last few days I started to dig into the world of F#. I got stuck on an lazy implementation of the Fibonacci-Sequence.
In almost every book covering functional programming you find an implementation of the following simple algorithm.
Unlike Haskell F# doesn't use lazy evaluation by default, which makes this implemenation quite ineffecient. So I thought it couldn't be too hard to add the laziness to the F# implementation. Here's my first result of an lazy implementation.
Unfortunately there is a problem with this implementation. The expression
(fib(n-1))
.Value, respectively(fib(n-2))
.Value doesn't evaluate lazily as I tested in the following exampleI've declared a lazy function called lazyFunc, which computes the square of x an prints a message, when it is evaluated. The output of this little programm contains two occurences of the sentence "lazyFunc was evaluated". From this output one can conclude that the function lazyFunc wasn't evaluated lazily.
But if you remove the parameter x from our function lazyFunc the lazy evaluation works as expected.
It seems like the lazy evaluation in F# only works with functions without parameters. But in my original Problem the function fib has one parameter. Is there a way to use lazy evaluation anyway?
Any help with this problem is appreciated.