I am new to OCaml, so I am learning the basics. I am writing a function that determines whether a list contains a given integer.
let rec int_member (x: int) (l: int list) : bool
begin match l with
| [] -> false
| hd :: rest -> x = hd || int_member rest x
end
as a test case...
let test (): bool =
(int_member 1 [1;2;3]) = true
;; run_test "contains 1 [1;2;3]" test
I am getting an error saying that "this expression has type int list but an expression was expected of type int". How can I fix this?
If you look at your recursive call, you should see that you're not passing the arguments quite right! Otherwise this code is quite good. (I see a missing =, and also using begin and end isn't very idiomatic OCaml here. You can just leave them out.)
int_member rest x
The first argument to int_member should be an int. You're passing an int list as the first argument. That's what the error message is complaining about.
You simply switched around the order of the arguments.
PS: The begin ... end in your code is superfluous.
Related
let log x = print_int x; log ;;
log 111 222;;
I am expecting log to print 111 and return itself and then print 222 on the second call but it does not work as expected, I am getting an error message instead. Why? How to make it work as expected?
I also tried rec to no avail.
File "./hello.ml", line 3, characters 8-11:
3 | log 111 222;;
^^^
Error: This expression has type int but an expression was expected of type
float
If you try this:
let log x = print_int x; log
You're returning the log that already exists, which has type float -> float, thus the type mismatch.
If you try:
let rec log x = print_int x; log
The type system is getting confused. Your log is taking an int and returning... a function that takes an int and returns a function that takes an int and returns...
This recursiveness doesn't work.
... Unless you enable recursive types.
% ocaml -rectypes
OCaml version 4.14.0
Enter #help;; for help.
# let rec log x = print_int x; log;;
val log : int -> 'a as 'a = <fun>
# log 222 111;;
222111- : int -> 'a as 'a = <fun>
Answers to the OP's next question detail why this option is not on by default.
Unless you declare log as recursive, its return value will be some other function, the previous definition of log. And, indeed, log is a function that takes a floating value and returns a floating value.
If you do declare log as recursive, you will have further problems. In particular, your function will have a recursive type. You can get this to work using the -rectypes flag.
(I would explain more fully, but #Chris has given a good explanation while I was writing this.)
I have a list lst of objects of type value where
type value = A of int | B of bool | C of string
In doing some matching on the the list, I tried to write
match lst with
| A x :: val :: tl -> ...
and got an exception saying that in the variable val a pattern was expected. I am assuming this is because in the head of the list I matched on a value variant, but for val I wanted to capture all possible next entries in the list. I can think of some ways around them, like writing several cases for the several variants of val. But since I want to do the same basic thing no matter what val is, that seems like a very inelegant solution. Is there a better solution?
Elaborating an answer based on glennsl's comment, I assume this snippet entered into the top level is reproducing the syntax error you're hitting:
since val is a reserved keyword, it is not legal to use it in pattern matches. The error is saying that the underlined token val is triggering a syntax error since it is expecting something that could be part of a pattern.
The following should compile without any problems (using some random values for example):
type value = A of int | B of bool | C of string
match [A 1; B true; C "foo"] with
| A x :: v :: tl -> Some (x, v)
| _ -> None
And this is simply due to the replacement of the keyword val with the variable v in the pattern.
I have the following function :
let extract n l =
let rec aux acc pro = function
|[] -> acc
|a::b -> if (List.length pro) = n then aux (pro::acc) [] (a::b) else aux acc (a::pro) b; aux acc (pro) b
in aux [] [] l
As you can see in my pattern matching at the second test's case I am calling two times the function. Is it possible ?
So it is possible to have this kind of function :
let rec some_function = function
| [] ->[]
| a::b -> some_function b; some_function b (*so I am calling two times the function in a single test*)
I am asking this question because here I have the following warning :
File "main.ml", line 4, characters 48-72:
Warning 10: this expression should have type unit.
So there is a problem at the exact place I called two times my recursive function.
It might be because I am using ; but in this case how could I seperate these two calls ?
Thank you !
To add onto FlorianWeimer's answer, some information about your error message.
Warning 10: this expression should have type unit.
OCaml is strongly typed. Therefore, if a function returns, say, an integer or a list, and you don't do anything with it, it'll wonder what's going on and warn you.
A function call like print_int 5; returns (), which is of type unit. That basically means that it returns nothing because you're not calling it to compute something, but to do something. It has done that thing and now it returns and you move on.
But a function call like float_of_int 5;, that returns a value (the float 5.0). You (probably) didn't call it to do something, but to compute something, and what it returns is what interests you. Same goes for arithmetic expressions like 3+6; or for straight up values like 10; or "abc"; or [];.
That's why, if you write one of these things that have a value and you don't use that value (in an assignment, or as a parameter of another function), OCaml warns you. It tells you "I computed something that I didn't assign, didn't return, and didn't use as the argument of something else. Usually, things of type unit are the only things like that. Are you sure you don't have a bug in your code?"
Sometimes you know what you're doing and you don't want that warning. In that case, you can call the ignore function. ignore will take anything and ignore it, returning (). For instance, ignore 5; or ignore (float_of_int 10); won't throw the "this expression should have type unit" warnings that you'd get with 5; or float_of_int 10;.
It is possible in the sense that the compiler accepts it, but it only makes sense if you do something with the result (or the function has a side effect). The classic example for two function calls is the recursive computation of the Fibonacci sequence:
let rec fib = function
| 0 -> 0
| 1 -> 1
| n -> fib (n - 1) + fib (n - 2)
Some functions in the List module fail when the argument is an empty list. List.rev is an example. The problem is the dreaded Value Restriction.
I met the same problem while trying to define a function that returns a list with all but the last element of a list:
let takeAllButLast (xs: 'a list) =
xs |> List.take (xs.Length - 1)
The function works well with nonempty lists, but a version that would handle empty lists fails:
let takeAllButLast (xs: 'a list) =
if List.isEmpty xs then []
else xs |> List.take (xs.Length - 1)
takeAllButLast []
error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list, etc.
I tried several things: making it an inline function, not specifying a type for the argument, specifying a type for the returned value, making the function depend on a type argument, and using the Option type to obtain an intermediate result later converted to list<'a>. Nothing worked.
For example, this function has the same problem:
let takeAllButLast<'a> (xs: 'a list) =
let empty : 'a list = []
if List.isEmpty xs then empty
else xs |> List.take (xs.Length - 1)
A similar question was asked before in SO: F# value restriction in empty list but the only answer also fails when the argument is an empty list.
Is there a way to write a function that handles both empty and nonempty lists?
Note: The question is not specific to a function that returns all but the last element of a list.
The function itself is completely fine. The function does not "fail".
You do not need to modify the body of the function. It is correct.
The problem is only with the way you're trying to call the function: takeAllButLast []. Here, the compiler doesn't know what type the result should have. Should it be string list? Or should it be int list? Maybe bool list? No way for the compiler to know. So it complains.
In order to compile such call, you need to help the compiler out: just tell it what type you expect to get. This can be done either from context:
// The compiler gleans the result type from the type of receiving variable `l`
let l: int list = takeAllButLast []
// Here, the compiler gleans the type from what function `f` expects:
let f (l: int list) = printfn "The list: %A" l
f (takeAllButLast [])
Or you can declare the type of the call expression directly:
(takeAllButLast [] : int list)
Or you can declare the type of the function, and then call it:
(takeAllButLast : int list -> int list) []
You can also do this in two steps:
let takeAllButLast_Int : int list -> int list = takeAllButLast
takeAllButLast_Int []
In every case the principle is the same: the compiler needs to know from somewhere what type you expect here.
Alternatively, you can give it a name and make that name generic:
let x<'a> = takeAllButLast [] : 'a list
Such value can be accessed as if it was a regular value, but behind the scenes it is compiled as a parameterless generic function, which means that every access to it will result in execution of its body. This is how List.empty and similar "generic values" are implemented in the standard library.
But of course, if you try to evaluate such value in F# interactive, you'll face the very same gotcha again - the type must be known - and you'll have to work around it anyway:
> x // value restriction
> (x : int list) // works
I am trying to implement the following:
let list = [1;2;3;4];;
if ((List.exists 3 list) = true)
print_string "element exists in list\n"
But it is giving me the error: This expression has type int list
but an expression was expected of type 'a -> bool
I am not sure what this means.
List.exists takes a function and a list, not a value and a list. For testing whether a value is in a list, use List.mem.
Your if looks like C syntax. In OCaml you need to use then (but you don't need the parentheses).
As a side comment, if e = true then ... is the same as if e then .... If you use good names for things, the latter is usually clearer.