It happens quite often that it is costly to calculate a property from a value. So it would be better to be able to store the property once it is calculated. I am wondering how to code this properly.
Let's take an example. Assume we have a type integer, and very often we need to calculate prime factors of a value of such type (let's assume the prime factors of a negative integer is None):
module I =
struct
type t = C of int
type pf = (int list) option
let calculate_prime_factors (x: t) : pf =
(* a costly function to calculate prime factors *)
... ...
let get_prime_factors (x: t) : pf =
calculate_prime_factors x
end
let () =
let v = I.C 100 in
let pf_1 = I.get_prime_factors v in
let pf_2 = I.get_prime_factors v in
let pf_3 = I.get_prime_factors v in
...
At the moment, get_prime_factors just calls calculate_prime_factors, as a consequence, all the calculations of pf_1, pf_2, pf_3 are time consuming. I would like to have a mechanism to enable storing prime factors inside the module, so that as long as the integer does not change, the second and third times of get_prime_factors just read what have been stored.
Does anyone know how to modify the module I to achieve this?
It is possible that we need references to make this mechanism possible (eg, let vr = ref (I.C 100) in ...). It is OK for me to use references. But I don't know how to trigger automatically calculate_prime_factors if the hold value (ie, !vr) is changed.
What you want to do is memoization, no ?
You could try this :
module I =
struct
type t = C of int
type pf = (int list) option
let calculate_prime_factors (x: t) : pf =
(* a costly function to calculate prime factors *)
... ...
module HI = Hashtbl.Make (struct
type t = C of int
let equal = (=)
let hash (C x) = x
end)
let get_prime_factors =
let h = Hashtbl.create 17 in
fun x ->
try Hashtbl.find h x
with
Not_found -> let pf = calculate_prime_factors x in
Hashtbl.add h x pf;
pf
end
let () =
let v = I.C 100 in
let pf_1 = I.get_prime_factors v in
let pf_2 = I.get_prime_factors v in
let pf_3 = I.get_prime_factors v in
...
You could adapt it for negative integers (with exceptions, for example, which is better than options) but I hope you get the idea.
Looks like, that you're looking for this solution:
module I = struct
type t = {
c : int;
mutable result : int option;
}
let create c = {c; result = None}
let calculate_prime_factors t = match t.result with
| Some r -> r
| None ->
let r = do_calculate t.c in
t.result <- Some r;
r
end
This is called memoizing. And this particular example can be solved even easier, with Lazy computations.
module I = struct
type t = int Lazy.t
let create c = lazy (do_calculate c)
let calculate_prime_factors = Lazy.force
end
I would do the following :
let get_prime_factors x =
match get x with
| None ->
let res = calculate_prime_factors x
in
begin
set x res ;
res
end
| Some res -> res
;;
You need a mutable data structure accessed by get and set. For instance, with a reference on a list (but you may prefer a hashtable) :
let my_storage = ref [] (* or something mutable *)
let get x =
if List.mem_assoc x !my_storage
then Some (List.assoc x !my_storage)
else None
let set x r =
my_storage := (x,r) :: !my_storage ;;
You can also use exceptions instead of the option type (None and Some _).
Related
I was studying references in SML.
I wrote the following code:
let
val f = (fn (s) => s := ref((!(!s)) + 2))
val x = ref (5)
val y = ref x
in
(f y ; !x)
end;
I'm trying to get to val it = 7 : int, although my program prints val it = 5 : int. I can't understand why. I am sure the problem is in the f function but can't understand why.
What I'm trying to do: f function should update the argument y to be ref(ref(7)) so x could be ref(7). but for some reason it doesn't work. What is the problem?
Updating y to point to a new ref does not update x. There's a new reference created during the call to f, let's call it z. Before the call we have:
x -> 5
y -> x
where -> is "points to". After the call it is:
x -> 5
y -> z
z -> 7
Edit: One possible way to actually update x is by defining f as follows:
val f = fn r => !r := 7
When invoking f y, this updates the reference pointed to by y, which is x. But whether that is the "right" solution depends on what you actually want to achieve.
As Andreas Rossberg suggests, val f = fn r => !r := 7 could be one way to update the int of an int ref ref to 7. But instead of 7 you could write anything. If, instead, you want to increase by two the int being pointed indirectly to, a hybrid between your attempt and Andreas'es suggestion could be
fun f r = !r := !(!r) + 2
Here, !r := ... means "dereference r to get the int ref it points to, and update that int ref so that it instead points to ...", and !(!r) + 2 means "dereference r twice to get the int it indirectly points to, and add two to it." At this point, you have not changed what r points to (like you do with s := ref ...), and you're using the value it points to indirectly using the double-dereference !(!r).
A test program for this could be:
val x = ref 5
val y = ref x
fun f r = !r := !(!r) + 2
fun debug str =
print ( str ^ ": x points to " ^ Int.toString (!x) ^ " and "
^ "y points indirectly to " ^ Int.toString (!(!y)) ^ ".\n" )
val _ = debug "before"
val _ = f y
val _ = debug "after"
Running this test program yields:
before: x points to 5 and y points indirectly to 5.
after: x points to 7 and y points indirectly to 7.
I have implemented a Table data type in haskell,but my minkey function which is supposed to return the smallest key seems not to give the right result. I am just wondering why..
module Table where
import Prelude hiding (init,read,length)
type Key = Int
type Value = String
errorvalue = "ERROR"
maxentries = 5
data Table = Empty | App(Key,Value,Table)
deriving Show
init :: Table
insert :: (Key,Value,Table) -> Table
isin :: (Key,Table) -> Bool
read :: (Key,Table) -> Value
empty :: Table -> Bool
delete :: (Key,Table) -> Table
update :: (Key,Value,Table) -> Table
length :: Table -> Int
full :: Table -> Bool
minkey::Table->Key
init = Empty
minkey(App(k,v,init))=k
minkey(App(k,v,t))= if k>minkey(t) then minkey(t) else k
insert(k,v,t) = if v == errorvalue then t
else if isin(k,t) then t
else if full(t) then t
else App(k,v,t)
isin(x,Empty) = False
isin(x,App(k,v,t)) = if x == k then True
else isin(x,t)
read(x,Empty) = errorvalue
read(x,App(k,v,t)) = if x == k then v
else read(x,t)
empty(Empty) = True
empty(App(k,v,t)) = False
delete(x,Empty) = Empty
delete(x,App(k,v,t)) = if x == k then t
else App(k,v,delete(x,t))
update(k,v,Empty) = Empty
update(k,v,App(k2,v2,t)) = if k == k2 then App(k,v,t)
else App(k2,v2,update(k,v,t))
length(Empty) = 0
length(App(k,v,t)) = 1 + length(t)
full(t) = if length(t) == maxentries then True
else False
In another script I initialized a table:
import Table
import Prelude hiding (init,read,length)
main :: IO ()
main = do
let k1 = 9
let k2 = 8
let k3 = 1
let k4 = 6
let k5 = 10
let v1 = "q"
let v2 = "a"
let v3 = "si"
let v4 = "se"
let v5 = "fu"
let i0 = init
let i1 = insert(k1,v1,i0)
let i2 = insert(k2,v2,i1)
let i3 = insert(k3,v3,i2)
let i4 = insert(k4,v4,i3)
let i5 = insert(k5,v5,i4)
let m = minkey(i5)
print m
print i5
When I print m the output is not 1 as I expected,but the last key imported to the table (in this case 10)
What am I doing wrong? Maybe the recursion?
minkey's init is regarded as argument name, not Empty, so pattern always matches on that line. Maybe GHC might have warned you as -Woverlapping-patterns.
If init can't be changed, then you may use case expression.
I tried to create a thread which does a calculation of the fibonacci-numbers. That worked fine, but then I tried to create another thread that stops the calculation-thread if it takes more than x seconds to calculate.
Here is my code:
module TimedFuture : sig
type 'a t
val create : ('a -> 'b) -> 'a -> float -> 'b t
val get : 'a t -> 'a option
end = struct
type 'a t = 'a Event.channel
let create f a t =
let c = Event.new_channel () in
let rec loop f = f (); loop f in
let task () =
let b = f a in
loop (fun () -> Event.(sync (send c b)))
in
let start_calc_thread () =
let t1 = Thread.create task () in
while ((Unix.gettimeofday () -. t) < 1.0) do
Printf.printf "Thread should keep running: %f\n"
(Unix.gettimeofday () -. t);
done;
try Thread.kill t1 with t1 -> ();
Printf.printf "Thread stoped\n"
in
let _ = Thread.create start_calc_thread () in
c
let get c = Some Event.(sync (receive c))
end
let option_to_i o = match o with
| None -> 0
| Some x -> x
let test =
let rec f x = match x with
| 1 -> 1
| 2 -> 1
| _ -> f (x-1) + f (x-2)
in
let t = Unix.gettimeofday () in
let ff = TimedFuture.create f 40 t in
Printf.printf "\nResult: %i\n" (option_to_i (TimedFuture.get ff)),
ff
When I compile the code and run it, the calculation thread doesn't stop working, although I get the "Thread stopped" in terminal.
Do you see my fault?
A thread can be interrupted in only specific cancellation points, in particular, in points where a user code passes control back to the runtime, so that the latter can do its work. One particular cancellation point is allocation. Since your code doesn't allocate, and reasonably implemented Fibonacci will not allocate either, it is not possible to stop it. If your real algorithm indeed doesn't have cancellation points, then you should either add them explicitly or use processes. To add explicit cancellation point, one can just add Thread.yield.
I have a big Excel file, which i read with Excel Provider in F#.
The rows should be grouped by some column. Processing crashes with OutOfMemoryException. Not sure whether the Seq.groupBy call is guilty or excel type provider.
To simplify it I use 3D Point here as a row.
type Point = { x : float; y: float; z: float; }
let points = seq {
for x in 1 .. 1000 do
for y in 1 .. 1000 do
for z in 1 .. 1000 ->
{x = float x; y = float y; z = float z}
}
let groups = points |> Seq.groupBy (fun point -> point.x)
The rows are already ordered by grouped column, e.g. 10 points with x = 10, then 20 points with x = 20 and so one. Instead of grouping them I need just to split the rows in chunks until changed. Is there some way to enumerate the sequence just once and get sequence of rows splitted, not grouped, by some column value or some f(row) value?
If the rows are already ordered then this chunkify function will return a seq<'a list>. Each list will contain all the points with the same x value.
let chunkify pred s = seq {
let values = ref []
for x in s do
match !values with
|h::t -> if pred h x then
values := x::!values
else
yield !values
values := [x]
|[] -> values := [x]
yield !values
}
let chunked = points |> chunkify (fun x y -> x.x = y.x)
Here chunked has a type of
seq<Point list>
Another solution, along the same lines as Kevin's
module Seq =
let chunkBy f src =
seq {
let chunk = ResizeArray()
let mutable key = Unchecked.defaultof<_>
for x in src do
let newKey = f x
if (chunk.Count <> 0) && (newKey <> key) then
yield chunk.ToArray()
chunk.Clear()
key <- newKey
chunk.Add(x)
}
// returns 2 arrays, each with 1000 elements
points |> Seq.chunkBy (fun pt -> pt.y) |> Seq.take 2
Here's a purely functional approach, which is surely slower, and much harder to understand.
module Seq =
let chunkByFold f src =
src
|> Seq.scan (fun (chunk, (key, carry)) x ->
let chunk = defaultArg carry chunk
let newKey = f x
if List.isEmpty chunk then [x], (newKey, None)
elif newKey = key then x :: chunk, (key, None)
else chunk, (newKey, Some([x]))) ([], (Unchecked.defaultof<_>, None))
|> Seq.filter (snd >> snd >> Option.isSome)
|> Seq.map fst
Lets start with the input
let count = 1000
type Point = { x : float; y: float; z: float; }
let points = seq {
for x in 1 .. count do
for y in 1 .. count do
for z in 1 .. count ->
{x = float x; y = float y; z = float z}
}
val count : int = 1000
type Point =
{x: float;
y: float;
z: float;}
val points : seq<Point>
If we try to evalute points then we get a OutOfMemoryException:
points |> Seq.toList
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at Microsoft.FSharp.Collections.FSharpList`1.Cons(T head, FSharpList`1 tail)
at Microsoft.FSharp.Collections.SeqModule.ToList[T](IEnumerable`1 source)
at <StartupCode$FSI_0011>.$FSI_0011.main#()
Stopped due to error
It might be same reason that groupBy fails, but I'm not sure. But it tells us that we have to use seq and yield to return the groups with. So we get this implementation:
let group groupBy points =
let mutable lst = [ ]
seq { for p in points do match lst with | [] -> lst <- [p] | p'::lst' when groupBy p' p -> lst <- p::lst | lst' -> lst <- [p]; yield lst' }
val group : groupBy:('a -> 'a -> bool) -> points:seq<'a> -> seq<'a list>
It is not the most easily read code. It takes each point from the points sequence and prepends it to an accumulator list while the groupBy function is satisfied. If the groupBy function is not satisfied then a new accumulator list is generated and the old one is yielded. Note that the order of the accumulator list is reversed.
Testing the function:
for g in group (fun p' p -> p'.x = p.x ) points do
printfn "%f %i" g.[0].x g.Length
Terminates nicely (after some time).
Other implementation with bug fix and better formatting.
let group (groupBy : 'a -> 'b when 'b : equality) points =
let mutable lst = []
seq {
yield! seq {
for p in points do
match lst with
| [] -> lst <- [ p ]
| p' :: lst' when (groupBy p') = (groupBy p) -> lst <- p :: lst
| lst' ->
lst <- [ p ]
yield (groupBy lst'.Head, lst')
}
yield (groupBy lst.Head, lst)
}
Seems there is no one line purely functional solution or already defined Seq method which I have overseen.
Therefore as an alternative here my own imperative solution. Comparable to #Kevin's answer but actually satisfies more my need. The ref cell contains:
The group key, which is calculated just once for each row
The current chunk list (could be seq to be conform to Seq.groupBy), which contains the elements in the input order for which the f(x) equals to the sored group key (requires equality).
.
let splitByChanged f xs =
let acc = ref (None,[])
seq {
for x in xs do
match !acc with
| None,_ ->
acc := Some (f x),[x]
| Some key, chunk when key = f x ->
acc := Some key, x::chunk
| Some key, chunk ->
let group = chunk |> Seq.toList |> List.rev
yield key, group
acc := Some (f x),[x]
match !acc with
| None,_ -> ()
| Some key,chunk ->
let group = chunk |> Seq.toList |> List.rev
yield key, group
}
points |> splitByChanged (fun point -> point.x)
The function has the following signature:
val splitByChanged :
f:('a -> 'b) -> xs:seq<'a> -> seq<'b * 'a list> when 'b : equality
Correctures and even better solutions are welcome
Is there a way to use functions in Discriminated Unions? I am looking to do something like this:
Type Test<'a> = Test of 'a-> bool
I know this is possible in Haskell using newtype and I was wondering what the equivalent in F# would be.
Thanks.
type Test<'A> = Test of ('A -> bool)
As an expansion on desco's answer you can apply the function tucked into Test with pattern matching:
type Test<'a> = Test of ('a -> bool)
// let applyTest T x = match T with Test(f) -> f x
// better: (as per kvb's comment) pattern match the function argument
let applyTest (Test f) x = f x
Example:
// A Test<string>
let upperCaseTest = Test (fun (s:string) -> s.ToUpper() = s)
// A Test<int>
let primeTest =
Test (fun n ->
let upper = int (sqrt (float n))
n > 1 && (n = 2 || [2..upper] |> List.forall (fun d -> n%d <> 0))
)
In FSI:
> applyTest upperCaseTest "PIGSMIGHTFLY";;
val it : bool = true
> applyTest upperCaseTest "PIGSMIgHTFLY";;
val it : bool = false
> [1..30] |> List.filter (applyTest primeTest);;
val it : int list = [2; 3; 5; 7; 11; 13; 17; 19; 23; 29]