I want to write a function that implements basic usage of grep: matching a pattern in a file. And I want to match_file_pattern to return a list of matched lines. But the code here cannot compile, the error is:
Error: This expression has type string list
but an expression was expected of type unit
And the code is:
let match_file pattern file_name =
let matched_lines = ref [] in
let ic = open_in file_name in
try
while true
do
let line = input_line ic in
if (Str.string_match (Str.regexp pattern) line 0)
then
matched_lines := line::!matched_lines
done;**(*!matched_lines*)**(*I need add this to compile successfully*)
with End_of_file ->
close_in ic;
List.rev !matched_lines;;
I think the error is caused by in ocaml, close_in ic; List.rev !matched_lines is grouped into a subexpression of "with" keyword, so its type should match with "try" expression. I try to find ways to break the relation between close_in ic; and List.rev !matched_lines, but failed.
You can use begin/end or parentheses:
let match_file pattern file_name =
let matched_lines = ref [] in
let ic = open_in file_name in
begin
try
while true
do
let line = input_line ic in
if (Str.string_match (Str.regexp pattern) line 0)
then
matched_lines := line::!matched_lines
done
with End_of_file -> close_in ic
end;
List.rev !matched_lines
The type of the loop is unit even though it never complete. The typechecker doesn't know that, so you need to make the expression under try have the same type as the exception handlers.
In this case you could use an arbitrary list such as [] but it's misleading for the reader, and doesn't generalize to cases where it may be more complicated to provide an expression of the correct type.
The idiomatic solution here is to place an assert false, which would raise an exception if ever evaluated. Unlike the infinite while loop, assert false is known by the typechecker to not return and it is compatible with any type since a value is never produced:
try
while true do
...
done;
assert false
with ... -> ...
Your code is just fine:
one semicolon after done, for sequencing of instructions, and then !matched_lines as return value of the try code part, then with ....
No ambiguities here. The compiler just doesn't take into account that End_of_file is always raised.
The rest is question of coding style. I like putting a (* never reached *) comment at these technically required expressions - would be a good idea for the assert false proposal as well IMO.
Related
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.
Since semicolons are apparently optional in Rust, why, if I do this:
fn fn1() -> i32 {
let a = 1
let b = 2
3
}
I get the error:
error: expected one of `.`, `;`, `?`, or an operator, found `let`
--> src/main.rs:3:9
|
2 | let a = 1
| - expected one of `.`, `;`, `?`, or an operator here
3 | let b = 2
| ^^^ unexpected token
They're not optional. Semicolons modify the behaviour of an expression statement so it should be a conscious decision whether you use them or not for a line of code.
Almost everything in Rust is an expression. An expression is something that returns a value. If you put a semicolon you are suppressing the result of this expression, which in most cases is what you want.
On the other hand, this means that if you end your function with an expression without a semicolon, the result of this last expression will be returned. The same can be applied for a block in a match statement.
You can use expressions without semicolons anywhere else a value is expected.
For example:
let a = {
let inner = 2;
inner * inner
};
Here the expression inner * inner does not end with a semicolon, so its value is not suppressed. Since it is the last expression in the block, its value will be returned and assigned to a. If you put a semicolon on this same line, the value of inner * inner won't be returned.
In your specific case, not suppressing the value of your let statement doesn't make sense, and the compiler is rightly giving you an error for it. In fact, let is not an expression.
Semicolons are generally not optional, but there are a few situations where they are. Namely after control expressions like for, if/else, match, etc.
fn main() {
let a: u32 = 5;
if 5 == a {
println!("Hello!");
}
if 5 == a {
println!("Hello!");
};
for x in "World".chars() {
println!("{}", x);
}
for x in "World".chars() {
println!("{}", x);
};
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1bf94760dccae285a2bdc9c44e8f658a
(There are situations where you do need to have or not have semicolons for these statements. If you're returning the value from within you can't have a semicolon, and if you're setting a variable to be the value from within you'll need a semicolon.)
Say I have the following statement logic (I'll be using VBA for this example, but it also pertains to other languages)
x = 1
y = 2
z = 1000
If x = 1 Or y = 2 Or z = 4 Then
Execute Code
End
Does the compiler or executing program find that the first value is true, and then continue to Execute Code or does it finish off the rest of the statement?
I can't speak for VBA, but I can say that it is language specific. In some languages, the programmer has the ability to use "short-circuit" AND and OR expressions. Short-circuiting is the process of no longer evaluating a boolean expression if the result has already been determined.
If using a short-circuited AND, the boolean operation stops early if a FALSE is found. If using a short-circuited OR, the boolean operation stops early if a TRUE is found.
For example, in Java:
a || b is a short-circuited OR
a | b is a non-short-circuited OR
a && b is a short-circuited AND
a & b is a non-short-circuited AND
Some may ask, "why would I ever use a non-short-circuited AND or OR?" The reason for this comes when you are calling a function that returns a boolean that you want to run in every case. For example a() | b() would run both function a and function b. a() || b() only runs function b if a returns false.
I think that also in vba you can use OrElse.
'Or' (bitwise comparison) always finishes the rest of the statement, 'OrElse' (logical comparison) stops when the requirement is met.
In C++, C# and Java you can use '|' and '||'.
For example if object is null Or object.value = "" will result in a null exception when the object is empty because of the attempt to access a field from an empty object.
With OrElse the evaluation if object is null OrElse object.value = "" will stop at the first comparison when an empty object is evaluated.
I have a very simple question. I'd like to use a where clause after a bloc of code that uses bind operators but I get a compilation error.
Here is a simple example:
main =
putStrLn "where clause test:" >>
return [1..10] >>= \list ->
print list'
where list' = reverse list -- test1.hs:5:28: Not in scope: `list'
I can use a let clause for list' as in
main =
putStrLn "where clause test:" >>
return [1..10] >>= \list ->
let list' = reverse list -- works of course
in print list'
but I'd really like it if I could use a where clause...
I also tried with do notation
main = do
putStrLn "where clause test:"
list <- return [1..10]
print list'
where list' = reverse list --test3.hs:5:30: Not in scope: `list'
Same problem. Can I use a where clause in these circumstances?
As ephemient explains, you can't use where clauses the way you do.
The error happens because in this code:
main =
return [1..10] >>= \list ->
print list'
where
list' = reverse list
The where-clause is attached to the main function.
Here's that same function with more parentheses:
main = return [1..10] >>= (\list -> print list')
where
list' = reverse list
I think its fairly obvious why you get the "out of scope" error: The binding for list is deep inside the main expression, not something the where clause can reach.
What I usually do in this situation (and I've been bitten by the same thing a bunch of times). I simply introduce a function and pass the list as an argument.
main = do
list <- return [1..10]
let list' = f list
print list'
where
f list = reverse list -- Consider renaming list,
-- or writing in point-free style
Of course, I imagine your actual code in the f function is a lot more that just reverse and that's why you want it inside a where clause, instead of an inline let binding. If the code inside the f function is very small, I'd just write it inside the let binding, and wouldn't go through the overhead of introducing a new function.
The problem is that let-in is an expression, which can be used inside other expressions, while where can only be used on a (module|class|instance|GADT|...) declaration or a (function|pattern) binding.
From the Haskell 98 report on declarations and bindings,
p | g1 = e1
| g2 = e2
…
| gm = em
where { decls }
is sugar for
p = let decls in
if g1 then e1 else
if g2 then e2 else
…
if gm then em else error "Unmatched pattern"
or, simplifying things by removing guards,
p = e where { decls }
is sugar for
p = let decls in e
in both function and pattern bindings. This is true even when your e is a do {…} construct.
If you want to have a binding local to a particular subexpression within a larger expression, you need to use let-in (or simply let inside a do, but that's just sugar for let-in).
You can't even write
main = do
putStrLn "where clause test: "
list <- return [1..10]
(print list' where list' = reverse list)
because "e where { decls }" is not a legal expression – where can only be used in declarations and bindings.
main = do
putStrLn "where clause test: "
list <- return [1..10]
let list' = list'' where list'' = reverse list
print list'
This is legal (if somewhat contrived).
As far as I can tell, the where clause is only used in local bindings. The inner part of a >>(=) binding statement is not a local binding (two different kinds of bindings in that sentence).
Compare with this:
main = f [1..10]
f list =
putStrLn "where clause test:" >> print list'
where list' = reverse list
You might want to refer to the Haskell 98 syntax report - not sure how much help it would be.
If I'm wrong, someone will certainly correct me, but I'm pretty sure you can't use a where clause at all in the style you've shown above. list will never be in scope to a where clause unless it's a parameter to the function.