Look at the following snippets:
if a
return
if a b
return
if (a b)
return
if a(b)
return
if a((b) -> c)
return
if (a (b) -> c)
return
if a (b) -> c
return
The last one won't compile and it will produce a misleading error message, unexpected if.
I would expect it to produce the same output as the previous two.
Why is it not allowed?
In the last example there is an ambiguity whether the return is part of the function, or of the if statement. If it's interpreted as part of the function, then it would be a syntax error as there is no body for the if statement.
if a (b) -> c
return
Could be interpreted as you expected:
if (a (b) -> c)
return
Or the indentation of the return is understood to be a continuation of the anonymous function:
if (a (b) -> c
return)
In this case it gives an error as there is no body to go with the if statement.
I'm not certain, but I assume it chooses to place the return inside the function as this is the closest context, and it hasn't been explicitly closed (eg. with parenthesis).
As an alternative, It's safe enough to use the parenthesis as you have, as it will fail with a compile error rather than giving you unexpected behaviour that would be dificult to debug.
If all you are doing is returning inside the if statement, you can use a trailing if:
return if a (b) -> c
Or execute the function first, then use the result in the if statement to make it more
verbose:
isValid = a (b) -> c
return if isValid
Related
I've created a type for lazy binary tree:
type 'a lBT = LEmpty | LNode of 'a * (unit -> 'a lBT) * (unit -> 'a lBT);;
and wanted to create an instance of it:
let exlBST = LNode(3, function() -> LEmpty, function() -> LEmpty);;
but I received this error:
Error: The constructor LNode expects 3 argument(s),
but is applied here to 2 argument(s)
Can you tell me what's going on? Isn't unit considered as an argument?
The argument to LNode is not parsed as you expect, a triple with two functions, but as a pair where the the second item is a function returning another pair. Use parentheses around at least the middle function, but preferably both for consistency, to make your intention explicit:
let exlBST = LNode (3, (function () -> LEmpty), (function () -> LEmpty));;
There are unfortunately a few of these weird parsing edge cases/ambiguities with OCaml's syntax. You'll learn to deal with it in time, but a good rule of thumb is: If in doubt, use parentheses (or begin/end when appropriate)
I am trying to write a code that calculate the size of a list.
Here is what I've done:
let rec l = function
| [] -> 0
| t::q -> 1 + l q
print_int(l ([1;2;3;4]))
The problem is that it's saying me :
It is applied to too many arguments; maybe you forgot a `;'.
When I put the double semicolon ;; at the end of the definition of l it works well, yet I've read that ;; is not useful at all if you are not coding in the REPL, so here I don't see why it's giving me this error.
The following
print_int(l [1;2;3;4])
is a toplevel expression. Such expression needs to be preceded by ;;:
;; print_int(l [1;2;3;4])
Another option is to make this toplevel expression a binding with
let () = print_int(l [1;2;3;4])
When parsing the code the parser advances until it hits l q. At this point there could be more arguments that should get applied to the function l. So the parser keeps going and the next thing it finds is the value print_int. Another argument to l. Which gives you your error.
The parser has no way of knowing that you had finished the code for the function l. In the top level the special token ;; is used to tell the parser that the input is finished and it should evaluate the code now. After that it starts paring the remaining input again.
Now why doesn't compiled code also have the ';;' token?
Simply because its not needed. In compiled code the line print_int(l [1;2;3;4]) is not valid input. That would be a statement you want to execute and functional languages have no such thing. Instead print_int(l [1;2;3;4]) is an expression that returns a value, () in this case, and you have to tell the compiler what to do with that value. A let () = tells the compiler to match it against (). And the let ... also tells the compiler that the previous let rec l ... has finished. So no special ;; token is needed.
Or think of it this way: In the top level there is an implicit let _ = if your input doesn't start with let. That way you can just type in some expression and see what it evaluates to without having to type let _ = every time. The ';;' token still means "evaluate now" though and is still needed.
I have two questions concerning OCaml.
Firstly, what does the == means when defining a type.
For example you can see at the end of this page the following code:
type compteur == int;;
Then what is the difference with:
type compteur = int;;
Moreover I have an other question concerning pattern matching.
How to say that you want to return nothing on a case.
For example let's say I have a function f that returns a boolean:
let rec f v = function
| t when t<v -> true
| t when t > v -> f (t-1)
| t when t = v -> (* here a code to say that you do nothing, and wait for the other recursive call *)
type compteur == int is a syntax error. The only valid way to define a type alias is with =, not ==. It's just a typo on the page you linked.
How to say that you want to return nothing on a case.
The only way to return nothing from a function would be to exit the program, raise an exception or loop (or recur) infinitely. Otherwise a function always returns a value.
here a code to say that you do nothing, and wait for the other recursive call
What other recursive call? In the case that t = v only the code for that case will run. There is no other code to wait on.
def success?
return #fhosts.empty? and #khosts.empty? and #shosts.any?
end
When I run that instance method, I get an error:
/home/fandingo/code/management/lib/ht.rb:37: void value expression
return #fhosts.empty? and #khosts.empty? and #shosts.any?
I'm confused by what's happening since this works
def success?
#fhosts.empty? and #khosts.empty? and #shosts.any?
# This also works
# r = #fhosts.empty? and #khosts.empty? and #shosts.any?
# return r
end
I'm coming from a Python background, and I don't want anything to do with implicit returns. Programming has plenty of landmines as it is.
If we have an arbitrary expression, E, that consists of boolean operations and and or together, here are some operations we could perform:
if E -- works
E -- works
* v = E -- works
return E -- broken
Why doesn't the last case work?
Edit: Actually v = E doesn't work. Only
v = Ei
is evaluated. Ei+1...k are ignored.
This is likely due to the very weak binding of and which causes it to parse out differently than you expect:
return x and y
This actually means:
(return x) and y
Since you're returning immediately it doesn't have a chance to evaluate the remainder of the expression.
Your version without return is correct:
x and y
This doesn't have a binding issue and is more idiomatic Ruby. Remember you only need to put an explicit return if you're trying to force an exit before the last line of the method. Being opposed to implicit returns is going to make your code look heavily non-Ruby. They're one of the reasons Ruby is so clean and simple, and how things like a.map { |v| v * 2 } works.
The When in Rome principle applies here. If you want to write Python-style Ruby you're going to be going against the grain. It's like saying "I don't like how you say X in your spoken language, so I'll just ignore that and do it my way."
This should also work:
return x && y
The && method is very strongly bound so return is the last thing evaluated here.
Or if you really want to use and for whatever reason:
return (x and y)
Here is the program to find the factorial of a number in Go:
func factorial(x uint) uint {
if x == 0 {
return 1
}
return x * (factorial(x - 1))
}
The output for this function when called on input 5 is 120. However, if I add an else statement I get an error.
func factorial(x uint) uint {
if x == 0 {
return 1
} else {
return x * (factorial(x - 1))
}
}
Error : function ends without a return statement
I added a return at the end :
func factorial(x uint) uint {
if x == 0 {
return 1
} else {
return x * (factorial(x - 1))
}
fmt.Println("this never executes")
return 1
}
and I get back the expected output of 120.
Why would the second case cause an error? Why in the third case even though the function never reaches the last return 1, it computes the correct output?
This is a well known problem of the compiler.
There is even an issue logged : http://code.google.com/p/go/issues/detail?id=65
In the words of one of the authors of the Go language:
The compilers require either a return or a panic to be lexically last
in a function with a result. This rule is easier than requiring full
flow control analysis to determine whether a function reaches the end
without returning (which is very hard in general), and simpler than
rules to enumerate easy cases such as this one. Also, being purely
lexical, the error cannot arise spontaneously due to changes in values
such as constants used in control structures inside the function.
-rob
From another comment in golang-nuts, we can infer it's not going to be "fixed" soon :
It's not a bug, it's a deliberate design decision.
-rob
Note that other languages like Java have rules allowing this else.
March 2013 EDIT - It just got changed in Go1.1 :
Before Go 1.1, a function that returned a value needed an explicit
"return" or call to panic at the end of the function; this was a
simple way to make the programmer be explicit about the meaning of the
function. But there are many cases where a final "return" is clearly
unnecessary, such as a function with only an infinite "for" loop.
In Go 1.1, the rule about final "return" statements is more
permissive. It introduces the concept of a terminating statement, a
statement that is guaranteed to be the last one a function executes.
Examples include "for" loops with no condition and "if-else"
statements in which each half ends in a "return". If the final
statement of a function can be shown syntactically to be a terminating
statement, no final "return" statement is needed.
Note that the rule is purely syntactic: it pays no attention to the
values in the code and therefore requires no complex analysis.
Updating: The change is backward-compatible, but existing code with
superfluous "return" statements and calls to panic may be simplified
manually. Such code can be identified by go vet.
And the issue I mentioned is now closed with status "Fixed".