I'm just learning f# so possibly I'm doing something very silly. Feel free to point me to the relevant documentation, I've searched but wasn't able to find. I am using Visual Studio 2010 beta on windows 7 (.Net 4.0).
Everything is going well with my first f# project. Well.. almost everything. In particular
I'm writing a very simple linear interpolation function, with the following code:
let linterp (x:double) (xvalues:double list) (yvalues:double list) =
let num_els = xvalues.Length
if x <= xvalues.Head then
let result = yvalues.Head
elif x >= (List.rev xvalues).Head then
let result = (List.rev yvalues).Head
else for idx in [0 .. num_els] do
if List.nth xvalues idx >= x then
let x0 = xvalues.Item idx
let y0 = yvalues.Item idx
let x1 = xvalues.Item (idx+1)
let y1 = yvalues.Item (idx+1)
let result = y0 + (y1-y0)/(x1-x0)*(x - x0)
result
and I am receiving a series of errors which completely elude my comprehension.
This is the list of errors and warnings:
"error in the return expression for this 'let'. Possible correct indentation" for the first, second and last "let".
"possible incorrect indentation: this token is offside of context started at position (39:10). Try indenting this token further or using standard formatting conventions " for the "if"
"incomplete structured construct at or before this point in expression" for the last line (result).
I will add that I had to sweat a bit to annotate the types, since for some reason unknown to me the compiler was able to infer correctly for the first list, but for the second the type was always inferred as unit Also, my original version didn't bind the name result, but simply "returned the expression", like in
if x <= xvalues.Head then
yvalues.Head
or in
else for idx in [0 .. num_els] do
if List.nth xvalues idx >= x then
let x0 = xvalues.Item idx
let y0 = yvalues.Item idx
let x1 = xvalues.Item (idx+1)
let y1 = yvalues.Item (idx+1)
y0 + (y1-y0)/(x1-x0)*(x - x0)
This leaves an error under the "for", saying that "This expression has type unit but is here used with type double" and that the "if" is possibly incorrectly indented.
I think that when I'll see the solution to this I'll feel silly, but I've been stuck on such a simple problem for more than an hour, so I am asking for your help.
Thanks in advance!
ps: I've checked that the tabs are correctly interpreted as spaces in the Tools->options->.... -> F#->Tabs menu
pps: this is my first question on SO :-)
Your problem is that something like
let result = yvalues.Head
is not a complete expression, and so it can't form the body of one of the branches of an if block. Your initial approach was correct, except that a for ... do loop doesn't return a meaningful value (it returns (), which is the only value of type unit, as the compiler is trying to explain; this is similar to void in languages like C#). Instead of the for loop, you'll want to use an expression that has the value you're looking for. The smallest change to your code would be to use a mutable value which you imperatively set in the loop. A more idiomatic approach would be to use a built in function like List.fold to condense the list to a single value. This is complicated by the fact that you need to access consecutive entries in your lists (and that you need to operate on both xvalues and yvalues simulataneously), which means you'd probably need to use List.zip and Seq.pairwise, which might reduce clarity for someone not used to F#.
Additionally, there are a few other changes you can apply to make your code more idiomatic. For instance, let x0 = xvalues.Item idx would more commonly be written let x0 = xvalues.[idx]. However, note that F# lists are immutable, linked lists, and therefore do not support fast random access. This is another reason to favor an approach that uses the built-in List operators.
let linterp x (xvalues:double list) (yvalues:double list) =
if x <= xvalues.Head then
yvalues.Head
elif x >= (List.rev xvalues).Head then
(List.rev yvalues).Head
else
let idx = List.findIndex (fun e -> e >= x) xvalues
let x0 = xvalues.Item idx
let y0 = yvalues.Item idx
let x1 = xvalues.Item (idx+1)
let y1 = yvalues.Item (idx+1)
y0 + (y1-y0)/(x1-x0)*(x - x0)
Related
I am trying to copy a the values of the first matrix to the second element by element. I don't understand why "<-" doesn't work for me when I want to set a new value. Here's the code:
let y=[|[|"true";"true";"false";"false"|];
[|"true";"false";"true";"false"|];
[|"false";"false";"true";"true"|];
[|"false";"true";"false";"true"|]|]
;;
let fill_array =
let l=Array.length x in
for i=0 to l-1 do
for j=0 to l-1 do
x.(i).(j)<-(y(i).(j))
done;
done;
x;;
I get the following-Error: This expression has type string array array
This is not a function; it cannot be applied.
Ideally this would be a bool array but I wanted to try string first.
You are missing a dot. In
x.(i).(j)<- y(i).(j)
y(i) is a function application whereas you wanted y.(i)
x.(i).(j)<- y.(i).(j)
Note that for an element-by-element copy, another option would be to use higher-order functions rather than low-level loops:
let copy x y =
Array.iteri (fun i xi ->
Array.iteri (fun j x -> y.(i).(j) <- x) xi
) x
In OCaml parlance, to copy means to create a copy of something. And for the process of filling the contents of one data structure with another, we use the word blit. It is rather OCaml-specific, and probably confusing but it is good to know as it will help you navigate the OCaml documentation. It is always good to know what is the name of a thing that you search :)
Copying
To copy a matrix just do Array.(map copy), e.g.,
let xs = Array.make 10 10 0
let ys = Array.(map copy) xs
let () =
ys.(0).(0) <- 1;
assert (xs.(0).(0) = 0)
Here, Array.(map copy) is using the local open feature of OCaml and is the same as Array.map Array.copy. The Array.map function creates a new array that faps each element of the original array using the provided function, in our case it is Array.copy. To copy a 3d matrix you can do Array.(map##map copy) and so on.
Blitting
If you want to copy your matrix into an existing matrix then the most efficient way would be to use Array.blit, e.g.,
let blit_matrix ~dst ~src =
Array.iteri (fun row dst ->
Array.blit src.(row) 0 dst 0 (Array.length src.(row))) dst
Working on an exercise for university class and cant seem to represent what I am trying to do with correct syntax in ocaml. I want the function sum_positive to sum all the positive integers in the list into a single int value and return that value.
let int x = 0 in
let rec sum_positive (ls: int list) = function
|h::[] -> x (*sum of positive ints in list*)
|[] -> 0
|h::t -> if (h >= 0) then x + h then sum_positive t else sum_positive t (*trying to ensure that sum_positive t will still run after the addition of x + h*)
On compiling I am met with this error,
File "functions.ml", line 26, characters 34-38:
Error: Syntax error
This points to the then then statement I have in there, I know it cannot work but I cant think of any other representations that would.
You have if ... then ... then which is not syntactically valid.
It seems what you're asking is how to write what you have in mind in a way that is syntactically valid. But it's not clear what you have in mind.
You can evaluate two expressions in OCaml sequentially (one after the other) by separating them with ;. Possibly that is what you have in mind.
However it seems to me your code has bigger problems than just syntax. It appears you're trying to use x as an accumulated sum for the calculation. You should be aware that OCaml variables like x are immutable. Once you say let x = 0, the value can't be changed later. x will always be 0. The expression x + h doesn't change the value of x. It just evaluates to a new value.
The usual way to make this work is to pass x as a function parameter.
I was getting an issue that had involved the parameter of , I believe it was because I was trying to add an int value to function of type int list. This is what I ended up with.
let rec sum_positive = function
|[] -> 0
|h::t -> if h > 0 then h + (sum_positive t) else sum_positive t
a lot simpler than I thought it out to be.
I'm facing a syntax error in the code below:
let sum list =
let current_sum = List.hd list in
for i = 1 to List.length list - 1 do
let counter = List.nth list i
current_sum = current_sum + counter
done;;
The error that I'm facing is here
done;
^^^^
Error: Syntax error
The code is supposed to sum up the current values of the list at each iteration, for example
sum [1;2;3;4];;
- : int list = [1; 3; 6; 10]
So I think I'm going about this in the right direction, what I don't understand is why this error keeps popping up?
The keyword in is missing in the let counter statement.
Another error that will pop after : current_sum is immutable. You will have to change this.
Another way to achieve your sum : use List.fold function.
Putting in shape the comments below :
let sum_l l =
let (r,_) = List.fold_left
(fun (a_l, a_i) x -> ((a_i + x) :: a_l , a_i+x))
([],0) l in
List.rev r;;
You have simply forgotten the in keywork in your line 4.
However, OCaml is a functional language, and you're trying to use an imperative method here.
Even though it will work when you solve your syntax error, it is not the way you would do this in OCaml. For example, a function summing up the elements of a integer list can be done with the following:
let sum = List.fold_left (+) 0;;
or even
let sum = List.reduce ~f:(+);;
if you're using the Core library.
EDIT
After reading the comments under another answer, I've understood what you're really trying to do:
# sum [1;2;3;4];;
- : int list = [1; 3; 6; 10]
And here is a way to do so, using OCaml's functional features:
let sum l =
let sums =
List.fold_left (fun l x -> match l with
| [] -> [x]
| h::t -> (x+h)::l) [] l
in List.rev sums;;
The code is more complicated than just computing the sum itself, but it does the trick.
Consider this OCaml code:
let coupe_inter i j cases =
let lcases = Array.length cases in
let low,_,_ = cases.(i)
and _,high,_ = cases.(j) in
low,high,
Array.sub cases i (j-i+1),
case_append (Array.sub cases 0 i) (Array.sub cases (j+1) (lcases-(j+1)))
Why the expression let ... and ... in is used in place of a let ... in let ... in sequence (like F# force you to do)? This construct seems quite frequent in OCaml code.
Thanks!
let x = a and y = b in c has the effect of defining x and y "simultaneously". This means that the order of evaluation (a after or before b) is unspecified (you must not assume that a will be evaluated before), and that x is not bound in b and y not bound in a, they are only available in c.
I rarely use this construction, because I have been bitten in the past by the evaluation order thing. I often use the recursive variant of it, let rec ... and ... in ... (where all variable bound are available everywhere), however, to define mutually recursive functions.
let rec even n = (n = 0) || odd (n - 1)
and odd n = (n <> 0) && even (n - 1)
In F# let ... and ... is prohibited, but you still can write:
let rec low,_,_ = cases.[i]
and _,high,_ = cases.[j]
As #gasche said, let rec ... and ... is mainly used for defining mutually recursive functions/types. I think using a sequence of let is more intuitive and less error-prone hence should be preferred.
How would you make the folowing code functional with the same speed? In general, as an input I have a list of objects containing position coordinates and other stuff and I need to create a 2D array consisting those objects.
let m = Matrix.Generic.create 6 6 []
let pos = [(1.3,4.3); (5.6,5.4); (1.5,4.8)]
pos |> List.iter (fun (pz,py) ->
let z, y = int pz, int py
m.[z,y] <- (pz,py) :: m.[z,y]
)
It could be probably done in this way:
let pos = [(1.3,4.3); (5.6,5.4); (1.5,4.8)]
Matrix.generic.init 6 6 (fun z y ->
pos |> List.fold (fun state (pz,py) ->
let iz, iy = int pz, int py
if iz = z && iy = y then (pz,py) :: state else state
) []
)
But I guess it would be much slower because it loops through the whole matrix times the list versus the former list iteration...
PS: the code might be wrong as I do not have F# on this computer to check it.
It depends on the definition of "functional". I would say that a "functional" function means that it always returns the same result for the same parameters and that it doesn't modify any global state (or the value of parameters if they are mutable). I think this is a sensible definition for F#, but it also means that there is nothing "dis-functional" with using mutation locally.
In my point of view, the following function is "functional", because it creates and returns a new matrix instead of modifying an existing one, but of course, the implementation of the function uses mutation.
let performStep m =
let res = Matrix.Generic.create 6 6 []
let pos = [(1.3,4.3); (5.6,5.4); (1.5,4.8)]
for pz, py in pos do
let z, y = int pz, int py
res.[z,y] <- (pz,py) :: m.[z,y]
res
Mutation-free version:
Now, if you wanted to make the implementation fully functional, then I would start by creating a matrix that contains Some(pz, py) in the places where you want to add the new list element to the element of the matrix and None in all other places. I guess this could be done by initializing a sparse matrix. Something like this:
let sp = pos |> List.map (fun (pz, py) -> int pz, int py, (pz, py))
let elementsToAdd = Matrix.Generic.initSparse 6 6 sp
Then you should be able to combine the original matrix m with the newly created elementsToAdd. This can be certainly done using init (however, having something like map2 would be maybe nicer):
let res = Matrix.init 6 6 (fun i j ->
match elementsToAdd.[i, j], m.[i, j] with
| Some(n), res -> n::res
| _, res -> res )
There is still quite likely some mutation hidden in the F# library functions (such as init and initSparse), but at least it shows one way to implement the operation using more primitive operations.
EDIT: This will work only if you need to add at most single element to each matrix cell. If you wanted to add multiple elements, you'd have to group them first (e.g. using Seq.groupBy)
You can do something like this:
[1.3, 4.3; 5.6, 5.4; 1.5, 4.8]
|> Seq.groupBy (fun (pz, py) -> int pz, int py)
|> Seq.map (fun ((pz, py), ps) -> pz, py, ps)
|> Matrix.Generic.initSparse 6 6
But in your question you said:
How would you make the folowing code functional with the same speed?
And in a later comment you said:
Well, I try to avoid mutability so that the code would be simple to paralelize in the future
I am afraid this is a triumph of hope over reality. Functional code generally has poor absolute performance and scales badly when parallelized. Given the huge amount of allocation this code is doing, you're not likely to see any performance gain from parallelism at all.
Why do you want to do it functionally? The Matrix type is designed to be mutated, so the way you're doing it now looks good to me.
If you really want to do it functionally, though, here's what I'd do:
let pos = [(1.3,4.3); (5.6,5.4); (1.5,4.8)]
let addValue m k v =
if Map.containsKey k m then
Map.add k (v::m.[k]) m
else
Map.add k [v] m
let map =
pos
|> List.map (fun (x,y) -> (int x, int y),(x,y))
|> List.fold (fun m (p,q) -> addValue m p q) Map.empty
let m = Matrix.Generic.init 6 6 (fun x y -> if (Map.containsKey (x,y) map) then map.[x,y] else [])
This runs through the list once, creating an immutable map from indices to lists of points. Then, we initialize each entry in the matrix, doing a single map lookup for each entry. This should take total time O(M + N log N) where M and N are the number of entries in your matrix and list respectively. I believe that your original solution using mutation takes O(M+N) time and your revised solution takes O(M*N) time.