I have some type
type my_type_name =
| A of (float * float)
| B of (float * float)
| E
;;
And I know that I have issue in my code, if p >= q in B (p, q) or A (p, q). So I want to make assertion in type, such that if I'll try to make A (5, 1) it will inform me.
Is it possible to make assertion in type constructor? How it should look like?
I'm trying to avoid something like that:
assert (p < q) ; A(p, q)
Cause I have a lot of A or B objects in code.
#Jeffrey Scofield already gave a fully accurate answer to this, but here is the example requested:
module type MY_TYPE =
sig
type my_type_name = private
| A of (float * float)
| B of (float * float)
| E
val a : float -> float -> my_type_name
val b : float -> float -> my_type_name
val e : my_type_name
end
module My_type : MY_TYPE =
struct
type my_type_name =
| A of (float * float)
| B of (float * float)
| E
let a p q = assert true; A (p, q)
let b p q = assert true; B (p, q)
let e = E
end
let () =
(* My_type.A (1., 2.); *) (* Type error - private type. *)
let x = My_type.a 1. 2. in
(* Can still pattern match. *)
match x with
| My_type.A (_, _) -> ()
| My_type.B (_, _) -> ()
| My_type.E -> ()
The body of the signature could be an .mli file instead and the body of My_type could be an .ml file. The key is that my_type_name is followed by the keyword private in MY_TYPE. This causes the direct use of the constructor at the bottom to be flagged as an error, forcing all construction to go through the functions a, b, e, where you can include assertions or arbitrary other expressions.
EDIT To make the functions look even more like the constructors, you can of course turn their arguments into tuple types. To make the module nearly transparent you can open it at the bottom. But these are matters of taste and up to you.
There's no straightforward way to put such an assertion into the type definition itself.
One good approach would be to define your type as an abstract type (in a module) and export functions for constructing values of the type. These will be the only way to produce values of the type, and you can include any assertions you like in the functions.
Update
As #antron points out, making the type private rather than abstract might be a better fit for your problem.
Related
I'm confused with the syntax "single colon" in OCaml.
Snippet:
let update_variable (old_state : state) (var_name : var) (new_value : value) : var -> value option =
fun x -> if x = var_name then Some new_value else old_state x
The type inference of this function is state->var->value->value option. I'm confused with the colon before the var->value option. What does it mean? Is an additional parameter omitted?
A colon in OCaml is used to indicate typing. Usually, when you see something like ident : type, it means you're indicating ident has type type. For instance, you could do something
let a : int = 3
This also extends to function definition; however, in this case, since there are many identifiers before the =, it may confuse you about which identifier is being typed. Well, it's actually the whole thing before that is typed, the idea being that it will match what you have in your code. For instance, if you have something like
let f (x : 'a) : 'b =
...
it means f : 'a -> 'b. You could understand it as
let (f (x : 'a)) : 'b =
...
even though this is not valid syntax. This is because when, in your code, you will see something like f x, you'll know it will have type 'b.
Please note that explicit typing is rarely used in OCaml. In this case it is being used to give update_variable a more specific type than would otherwise be inferred.
Consider a simple, contrived example:
utop #
type foo = Foo
let f a b = a = b
let g (a : foo) (b : foo) = a = b;;
type foo = Foo
val f : 'a -> 'a -> bool = <fun>
val g : foo -> foo -> bool = <fun>
Without explicit type hints, in function f there is nothing know about parameters a and b except that they must be the same type.
We'd get the same behavior in g except that we've explicitly told it a and b must be of type foo. We can achieve the same by only specifying the type of one of the two parameters.
utop #
let h (a : foo) b = a = b;;
val h : foo -> foo -> bool = <fun>
I have written this helper function in OCaml and it keeps throwing this error.
code:
let rec helper1 f lines d =
match lines with
| [] -> None
| h::t when ( helper2 f h 0) <> -1 -> Some (d, (helper2 f h 0))
| _::t -> helper1 f t d+1;;
error:
|_::t -> helper1 f t d+1;;
^^^^^^^^^^^^^
Error: This expression has type ('a * int) option
but an expression was expected of type int
I need to have the type as ('a *int) option and according to me it looks okay. I am new to OCaml and any help would be appreciated!
It a common problem when learning OCaml. You are assuming that,
f x+1
is interpreter as
f (x+1)
while in fact it means,
(f x) + 1
More formally, in OCaml the function application operator, which is denoted just as a juxtaposition of the function name and its arguments, has higher precedence (binds tighter, evaluated before) than infix operators (e.g., +, -, *, etc).
Now the error message has a clear explanation since you have
helper1 f t d + 1
the compiler sees that you add something (helper1 f t d) to 1 and infers that this something should have type int. On the other hand, from the other occurrences of helper1 it also infers that it has type ('a * int) option, which is clearly not an int. So it indicates an error.
I know this could be stupid question, but since I'm new to Ocaml, please give me some tips on defining functions with specific type.
I want to define function which type has int * int * (int -> int) -> int
So I made a function like this.
let rec sigma a b func:int->int=
if a >= b then func(a)
else func(a) + sigma(a+1, b, func)
But sigma function here does not have type int * int * (int->int) -> int. Instead its type is int->int->(int->int)->int.
How should I define function sigma to have type int * int * (int->int) -> int?
(Error Message :
Error: This expression has type 'a * 'b * 'c
but an expression was expected of type int
The type int * int * (int->int) -> int denotes a function that takes a 3-tuple and returns and integer. A tuple (pair, triple, quadruple, etc) is written as (a,b,c,...), e.g.,
let rec sigma (a,b,func) : int =
if a >= b then func(a)
else func(a) + sigma(a+1, b, func)
With all that said, it is usually a bad idea to pass arguments via tuples in OCaml. It hampers currying, inefficient (each tuple is boxed into a separate value), and in general non-functional and not nice.
Also, when you constrain a parameter of a function, you shall parenthesize it, e.g., (func : int -> int).
And normally functions in OCaml are applied by juxtaposition of a function name and its arguments, e.g., given a function add
let add x y = x + y
we can apply (call it) just as add 3 5 (not add(3,5)!)
Therefore, the conventional way to define your sigma function would be
let rec sigma a b func : int =
if a >= b then func a
else func a + sigma (a+1) b func
In OCaml, I want to define a function f that accepts an input to update a record x. Among the following two approaches, I'm interested whether one has an advantage over the other (readability aside).
Variant approach
type input =
| A of int
| B of string
let f x = function
| A a -> { x with a }
| B b -> { x with b }
GADT approach
type _ input =
| A : int input
| B : string input
let f (type t) x (i: t input) (v: t) =
match i with
| A -> { x with a = v }
| B -> { x with b = v }
ADT pros:
Straightforward, no need for type annotations or anything fancy
Writing a function of type string -> input is straightforward.
GADT pros:
Avoid one layer of boxing.
However, this is completely negated if you need a parsing functions, which would force you to pack things under an existential.
To be more precise, the GADT version can be seen as a decomposition of the ADT version. You can transform one into the other in a systematic way, and the memory layout will be similar (with the help of a small annotation):
type a and b and c
type sum =
| A of a
| B of b
| C of c
type _ tag =
| A : a tag
| B : b tag
| C : c tag
type deppair = Pair : ('a tag * 'a) -> deppair [##ocaml.unboxed]
let pack (type x) (tag : x tag) (x : x) = Pair (tag, x)
let to_sum (Pair (tag, v)) : sum = match tag with
| A -> A v
| B -> B v
| C -> C v
let of_sum : sum -> deppair = function
| A x -> pack A x
| B x -> pack B x
| C x -> pack C x
As you noticed (non)readability of GADTs is a big drawback. Try to avoid GADTs when possibly. Easier to type and easier to read. Less complex error messages too.
Simplified at runtime they are the same. They are represented as simple ints or blocks with tag and fields and the code uses the tag to match and branch. So neither gives you an advantage there.
At compile time GADTs are more powerful as the compiler can check types in ways that ADTs don't allow. One example are existential types like the example in the other answer. So use GADTs when you can't use ADTs.
I would like to iterate over all combinations of elements from a list of lists which have the same length but not necessarily the same type. This is like the cartesian product of two lists (which is easy to do in OCaml), but for an arbitrary number of lists.
First I tried to write a general cartesian (outer) product function which takes a list of lists and returns a list of tuples, but that can't work because the input list of lists would not have elements of the same type.
Now I'm down to a function of the type
'a list * 'b list * 'c list -> ('a * 'b * 'c) list
which unfortunately fixes the number of inputs to three (for example). It's
let outer3 (l1, l2, l3) =
let open List in
l1 |> map (fun e1 ->
l2 |> map (fun e2 ->
l3 |> map (fun e3 ->
(e1,e2,e3))))
|> concat |> concat
This works but it's cumbersome since it has to be redone for each number of inputs. Is there a better way to do this?
Background: I want to feed the resulting flat list to Parmap.pariter.
To solve your task for arbitrary ntuple we need to use existential types. We can use GADT, but they are close by default. Of course we can use open variants, but I prefer a little more syntactically heavy but more portable solution with first class modules (and it works because GADT can be expressed via first class modules). But enough theory, first of all we need a function that will produce the n_cartesian_product for us, with type 'a list list -> 'a list list
let rec n_cartesian_product = function
| [] -> [[]]
| x :: xs ->
let rest = n_cartesian_product xs in
List.concat (List.map (fun i -> List.map (fun rs -> i :: rs) rest) x)
Now we need to fit different types into one type 'a, and here comes existential types, let's define a signature:
module type T = sig
type t
val x : t
end
Now let's try to write a lifter to this existential:
let int x = (module struct type t = int let x = x end : T)
it has type:
int -> (module T)
Let's extend the example with few more cases:
let string x = (module struct type t = string let x = x end : T)
let char x = (module struct type t = char let x = x end : T)
let xxs = [
List.map int [1;2;3;4];
List.map string ["1"; "2"; "3"; "4"];
List.map char ['1'; '2'; '3'; '4']
]
# n_cartesian_product xxs;;
- : (module T) list list =
[[<module>; <module>; <module>]; [<module>; <module>; <module>];
[<module>; <module>; <module>]; [<module>; <module>; <module>];
...
Instead of first class modules you can use other abstractions, like objects or functions, if your type requirements allow this (e.g., if you do not need to expose the type t). Of course, our existential is very terse, and maybe you will need to extend the signature.
I used #ivg 's answer but in a version with a GADT. I reproduce it here for reference. In a simple case where only the types float and int can appear in the input lists, first set
type wrapped = Int : int -> wrapped | Float : float -> wrapped
this is a GADT without type parameter. Then
let wrap_f f = Float f
let wrap_i i = Int f
wrap types into the sum type. On wrapped value lists we can call n_cartesian_product from #ivg 's answer. The result is a list combinations: wrapped list list which is flat (for the present purposes).
Now to use Parmap, i have e.g. a worker function work : float * int * float * float -> float. To get the arguments out of the wrappers, I pattern match:
combinations |> List.map (function
| [Float f1; Int i; Float f2; Float f3] -> (f1, i, f2, f3)
| _ -> raise Invalid_argument "wrong parameter number or types")
to construct the flat list of tuples. This can be finally fed to Parmap.pariter with the worker function work.
This setup is almost the same as using a regular sum type type wrapsum = F of float | I of int instead of wrapped. The pattern matching would be the same; the only difference seems to be that getting a wrong input, e.g. (F 1, I 1, F 2.0, F, 3.0) would be detected only at runtime, not compile time as here.