Nest let syntax from ocaml - syntax

I'm just starting to learn Rust and I'm coming from an OCaml background.
One thing that I often use is nested let expressions, in order to group related code together.
let x =
let y = 42 in
y + 1
in
...
My naive translation of this to rust would be:
let x =
let y = 42;
y + 1
;
However this fails to compile.
Is this type of syntax possible, or is it heavily frowned upon and thus is not supported?

Rust uses curly braces to delimit scopes. This works fine:
let x = {
let y = 42;
y + 1
};

Related

How can I emulate the results of this if then then statement while using correct syntax?

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.

is there a formula to get a term from nested loop?

I have a nested loop as follows :
xl = yl = [a for a in range(1,12)]
ll = [a for a in range(0,6)]
c = 0;
output = []
for x in xl:
for y in yl:
if (y > x):
for l in ll :
output.append("{0}-{1}-{2}".format(x,y,l));
c+=1;
Given a value of c which is the position of a certain term, I need to get the value of that term.
For example if c = 10, I need the 10th element of output.
it would be awesome if someone told could give me a generic formula for all nested loops.
I tried googling, but I don't even know what terms to google.
Well you have put the output into an array, so you can simply look at output[10].
As for the bigger problem that you are trying to solve, I believe that you want to learn about generators. Here is how you work with them. First you put your loop in a function, and call yield where you want and no return statement. Like so.
def loop_generator ():
xl = yl = [a for a in range(1,12)]
ll = [a for a in range(0,6)]
for x in xl:
for y in yl:
if (y > x):
for l in ll :
yield (x, y, 1)
Now x = loop_generator() will return a generator. This is an object that, every time you call next on it, will start running code in the function and will return the next point yield would be called. If you run out of yields it will raise the StopIteration exception.
So your code now can be finished off with:
my_generator = loop_generator()
# Throw away 9 values
for i in range(9):
next(my_generator)
# Get the one I want
x, y, l = next(my_generator)
# Show what I got.
print "{0}-{1}-{2}".format(x,y,l)
This strategy can be used to turn any nested loop into something that you can step through and pull values out of.
Incidentally Python's native looping constructs all know to call next and terminate cleanly on StopIteration so that the following works as you might hope:
for x, y, l in loop_generator():
print "{0}-{1}-{2}".format(x,y,l)

Let and construct versus let in sequence

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.

Copying fields in OCaml

I have a very basic question regarding OCaml records. Suppose I have a record defined:
type r = {a: int; b: int; c: int}
let x = {a=3; b=8; c=2}
Now, suppose I want to create a new record which has all fields equal to x but which has c=4. I could write:
let y = {a=3; b=8; c=4}
but this is annoying because there's not need to re-write a=3 and b=8. I could also write:
let y = {a=x.a; b=x.b; c=4}
but this is still not good if the record has many fields. Is there any way of writing something like:
let y = {x with c=4}
or something of the sort?
yeah, and that's the exact syntax.
let y = {x with c=4}

Indentation problem in f# (vs2010 beta1)

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)

Resources