Search code examples
linqf#lazy-evaluationcomputation-expression

How to make f# query expressions reusable?


i am trying to get accustomed with f# query expressions.

First of all, they are definitely eager, because:

let arr = [1; 2; 3]
let q = query { for item in arr do select item; count };;

val arr : int list = [1; 2; 3]
val q : int = 3

I want to reuse that query, so I try lazy computation:

let arr = ref [1; 2; 3]
let q = lazy query { for item in !arr do select item; count }
q.Value;;

val arr : int list ref = {contents = [1; 2; 3];}
val q : Lazy<int> = 3
val it : int = 3

Now, i want to re-evalute the query:

arr := [1; 2; 3; 4]
q.Force();;

val it : int = 3

So, nothing happened, it wouldn't recalculate. How can I use the query several times without redefining it?


Solution

  • It is hard to say what the best approach is based on your very minimal example, but the simplest way to write reusable code is to write a function:

    let q (arr:seq<'T>) = 
      query { for item in arr do select item; count };;
    

    And then you can reuse it just by calling it:

    > q [1;2;3];;
    val it : int = 3
    > q [1;2;3;4];;
    val it : int = 4