I'd like make a Set module containing functions. But there seems to be no way to compare functions, which Set needs. This obvious-looking thing compiles:
module Action = struct
type t = unit -> unit
let compare : t -> t -> int = Stdlib.compare
end
module Actions = Set.Make(Action)
But if I attempt to use it:
Fatal error: exception Invalid_argument("compare: functional value")
I just want compare that the functions are the same object, I am not trying to do something silly like compare them for equal behaviour.
Am I supposed to use something from the Obj module here?
The semantics of Stdlib.compare is to look arbitrarily deep inside the objects to see how their subparts compare. This doesn't really work for functions, as you point out. So OCaml doesn't allow compare to be applied to functions.
There isn't really a useful order that can be applied to functions, even if you're willing to use physical equality. Function values are immutable and can be duplicated or moved physically by the runtime system, at least in theory.
Since the ordering would necessarily be arbitrary, you can get the same effect by making your own arbitrary order: pair the functions with an int value that increases monotonically as you create new pairs.
Add an identity to your actions, e.g., you can compare actions by name,
module Action = struct
type t = {
name : string;
func : (unit -> unit);
}
let compare x y = String.compare x.name y.name
end
You should also ensure that all actions have different names, for example by introducing a global hash table that records all created actions. Make sure that actions are only creatable via the Action module, by adding an appropriate signature.
OCaml Stdlib compare documentation states ...
val compare : 'a -> 'a -> int
compare x y returns 0 if x is equal to y, a negative integer if x is less than y, and a positive integer if x is greater than y. The ordering implemented by compare is compatible with the comparison predicates =, < and > defined above, with one difference on the treatment of the float value nan. Namely, the comparison predicates treat nan as different from any other float value, including itself; while compare treats nan as equal to itself and less than any other float value. This treatment of nan ensures that compare defines a total ordering relation.
compare applied to functional values may raise Invalid_argument. compare applied to cyclic structures may not terminate.
The compare function can be used as the comparison function required by the Set.Make and Map.Make functors, as well as the List.sort and Array.sort functions.
Now we have two notion(s) of equality in OCaml, namely...
Structural Equality: Expressed using operator =, the type of which is
# (=);;
- : 'a -> 'a -> bool = <fun>
Physical Equality: Expressed using operator ==, the type of which is
# (==);;
- : 'a -> 'a -> bool = <fun>
As we can see, the type of both is same, but the function application of both of them is different when it comes to function value as arguments.
Structural Equality doesn't hold over function values, but Physical Equality may. Trying to compare(as in =) with function values throws. And as stated in the documentation of Stdlib.compare, it uses structural equality.
Illustration: Structural Equality with Function Values
# let f x = x;;
val f : 'a -> 'a = <fun>
# let g x = x;;
val g : 'a -> 'a = <fun>
# f = g;;
Exception: Invalid_argument "compare: functional value".
# g = f;;
Exception: Invalid_argument "compare: functional value".
Illustration: Physical Equality with Function Values
# let f x = x;;
val f : 'a -> 'a = <fun>
# let g x = x;;
val g : 'a -> 'a = <fun>
# f == g;;
- : bool = false
# f == f;;
- : bool = true
# g == g;;
- : bool = true
# g == f;;
- : bool = false
# let h x y = x + y;;
val h : int -> int -> int = <fun>
# h == f;;
Error: This expression has type int -> int
but an expression was expected of type int -> int -> int
Type int is not compatible with type int -> int
So in short, I don't think we can use Stdlib.compare with Set.Make with function values.
So ...
Either, we will have to keep the type t in Action module to something over which structural equality can be applied if we have to continue using Stdlib.compare.
Or, implement compare of your own so that it can do something with those function values as arguments, along with satisfying the function contract of val compare : t -> t -> int as mandated by Set.OrderedType module type.
WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET
Related
I'm trying to write a function that checks whether a set (denoted by a list) is a subset of another.
I already wrote a helper function that gives me the intersection:
let rec intersect_helper a b =
match a, b with
| [], _ -> []
| _, [] -> []
| ah :: at, bh :: bt ->
if ah > bh then
intersect_helper a bt
else if ah < bh then
intersect_helper at b
else
ah :: intersect_helper at bt
I'm trying to use this inside of the subset function (if A is a subset of B, then A = A intersect B):
let subset a_ b_ =
let a = List.sort_uniq a_
and b = List.sort_uniq b_
in intersect_helper a b;;
Error: This expression has type 'a list -> 'a list but an expression was expected of type 'b list
What exactly is wrong here? I can use intersect_helper perfectly fine by itself, but calling it with lists here does not work. From what I know about 'a, it's just a placeholder for the first argument type. Shouldn't the lists also be of type 'a list?
I'm glad you could solve your own problem, but your code seems exceedingly intricate to me.
If I understood correctly, you want a function that tells whether a list is a subset of another list. Put another way, you want to know whether all elements of list a are present in list b.
Thus, the signature of your function should be
val subset : 'a list -> 'a list -> bool
The standard library comes with a variety of functions to manipulate lists.
let subset l1 l2 =
List.for_all (fun x -> List.mem x l2) l1
List.for_all checks that all elements in a list satisfy a given condition. List.mem checks whether a value is present in a list.
And there you have it. Let's check the results:
# subset [1;2;3] [4;2;3;5;1];;
- : bool = true
# subset [1;2;6] [4;2;3;5;1];;
- : bool = false
# subset [1;1;1] [1;1];; (* Doesn't work with duplicates, though. *)
- : bool = true
Remark: A tiny perk of using List.for_all is that it is a short-circuit operator. That means that it will stop whenever an item doesn't match, which results in better performance overall.
Also, since you specifically asked about sets, the standard library has a module for them. However, sets are a bit more complicated to use because they need you to create new modules using a functor.
module Int = struct
type t = int
let compare = Pervasives.compare
end
module IntSet = Set.Make(Int)
The extra overhead is worth it though, because now IntSet can use the whole Set interface, which includes the IntSet.subset function.
# IntSet.subset (IntSet.of_list [1;2;3]) (IntSet.subset [4;2;3;5;1]);;
- : bool = true
Instead of:
let a = List.sort_uniq a_
Should instead call:
let a = List.sort_uniq compare a_
I've been learning OCaml recently and as of now it would seem an arrow is used by the compiler to signify what the next type would be. For instance, int -> int -> <fun> an integer which returns an integer, which returns a function.
However, I was wondering if I can use it natively in OCaml code. In addition, if anyone would happen to know the appropriate name for it. Thank you.
The operator is usually called type arrow where T1 -> T2 represents functions from type T1 to type T2. For instance, the type of + is int -> (int -> int) because it takes two integers and returns another one.
The way -> is defined, a function always takes one argument and returns only one element. A function with multiple parameters can be translated into a sequence of unary functions. We can interpret 1 + 2 as creating a +1 increment function (you can create it by evaluating (+) 1 in the OCaml command line) to the number 2. This technique is called Currying or Partial Evaluation.
Let's have a look at OCaml's output when evaluating a term :
# 1 + 2;;
- : int = 3
# (+) 1 ;;
- : int -> int = <fun>
The term1+2 is of type integer and has a value of 3 and the term (+) 1 is a function from integers to integers. But since the latter is a function, OCaml cannot print a single value. As a placeholder, it just prints <fun>, but the type is left of the =.
You can define your own functions with the fun keyword:
# (fun x -> x ^ "abc");;
- : bytes -> bytes = <fun>
This is the function which appends "abc" to a given string x. Let's take the syntax apart: fun x -> term means that we define a function with argument x and this x can now appear within term. Sometimes we would like to give function names, then we use the let construction:
# let append_abc = (fun x -> x ^ "abc") ;;
val append_abc : bytes -> bytes = <fun>
Because the let f = fun x -> ... is a bit cumbersome, you can also write:
let append_abc x = x ^ "abc" ;;
val append_abc : bytes -> bytes = <fun>
In any case, you can use your new function as follows:
# append_abc "now comes:" ;;
- : bytes = "now comes:abc"
The variable x is replaced by "now comes:" and we obtain the expression:
"now comes:" ^ "abc"
which evaluates to "now comes:abc".
#Charlie Parker asked about the arrow in type declarations. The statement
type 'a pp = Format.formatter -> 'a -> unit
introduces a synonym pp for the type Format.formatter -> 'a -> unit. The rule for the arrow there is the same as above: a function of type 'a pp takes a formatter, a value of arbitrary type 'a and returns () (the only value of unit type)
For example, the following function is of type Format.formatter -> int -> unit (the %d enforces the type variable 'a to become int):
utop # let pp_int fmt x = Format.fprintf fmt "abc %d" x;;
val pp_int : formatter -> int -> unit = <fun>
Unfortunately the toplevel does not infer int pp as a type so we don't immediately notice(*). We can still introduce a new variable with a type annotation that we can see what's going on:
utop # let x : int pp = pp_int ;;
val x : int pp = <fun>
utop # let y : string pp = pp_int ;;
Error: This expression has type formatter -> int -> unit
but an expression was expected of type
string pp = formatter -> string -> unit
Type int is not compatible with type string
The first declaration is fine because the type annotation agrees with the type inferred by OCaml. The second one is in conflict with the inferred type ('a' can not be both int and string at the same time).
Just a remark: type can also be used with records and algebraic data types to create new types (instead of synonyms). But the type arrow keeps its meaning as a function.
(*) Imagine having multiple synonymes, which one should the toplevel show? Therefore synonyms are usually expanded.
The given answer doesn't work for ADTs, GADTs, for that see: In OCaml, a variant declaring its tags with a colon
e.g.
type 'l generic_argument =
| GenArg : ('a, 'l) abstract_argument_type * 'a -> 'l generic_argument
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.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am new in SML and it is my first time to learn a functional language. I suppose there is abstraction of SML. I have not found perfect explanation of how to achieve abstraction in SML. Does anyone can offer a explanation?
Generally speaking, there are at least two forms of "abstraction" in programming:
Abstracting the client (parameterisation)
Abstracting the implementation (encapsulation)
(If you care, these correspond to universal and existential quantification in logic and type theory.)
In ML, parameterisation can be done on two levels. Either in the small, using functions (abstraction over values) and polymorphism (abstraction over types). Note in particular that functions are first-class, so you can parameterise one function over another. For example:
fun map f [] = []
| map f (x::xs) = f x :: map f xs
abstracts list transformation over the transforming function f as well as the element types.
In the large, parameterisation can be done using the module system: a functor abstracts a whole module over another module (i.e., over both values and types). For example, you could also write the map function as a functor:
functor Mapper(type t; type u; val f : t -> u) =
struct
fun map [] = []
| map (x::xs) = f x :: map xs
end
But usually you use functors for mass abstraction, i.e., in cases where there is more than just a single function you need to parameterise.
Encapsulation is also achieved by using modules. Specifically, by sealing them, i.e., hiding details of their types behind a signature. For example, here is a (naive) implementation of integer sets:
signature INT_SET =
sig
type set
val empty : set
val add : int * set -> set
val mem : int * set -> bool
end
structure IntSet :> INT_SET = (* ':>' hides the implementation of type set *)
struct
type set = int list
val empty = []
fun add(x, s) = x::s
fun mem(x, s) = List.exists (fn y => y = x) s
end
Outside the structure IntSet, its type set is fully abstract, i.e., it cannot be interchanged with lists. That is the purpose of the so-called sealing operator :> for modules.
Both forms of abstraction can occur together. For example, in ML one would usually implement a set as a functor:
signature ORD =
sig
type t
val compare : t * t -> order
end
signature SET =
sig
type elem
type set
val empty : set
val add : elem * set -> set
val mem : elem * set -> bool
end
functor Set(Elem : ORD) :> SET where type elem = Elem.t =
struct
type elem = Elem.t
datatype set = Empty | Branch of set * elem * set
val empty = Empty
fun add(x, Empty) = Branch(Empty, x, Empty)
| add(x, Branch(l, y, r)) =
case Elem.compare(x, y) of
LESS => Branch(add(x, l), y, r)
| EQUAL => Branch(l, y, r)
| GREATER => Branch(l, y, add(x, r))
fun mem(x, Empty) = false
| mem(x, Branch(l, y, r)) =
case Elem.compare(x, y) of
LESS => mem(x, l)
| EQUAL => true
| GREATER => mem(x, r)
end
This implementation of sets works for any type for which an ordering function can be provided. Unlike the naive implementation before, it also uses a more efficient search tree as its implementation. However, that is not observable outside, because the type's implementation is again hidden.
SML programs frequently are build on a descriptive types for the problem at hand. The language then uses pattern matching to figure out what case your are working with.
datatype Shape = Circle of real | Rectangle of real*real | Square of real
val a = Circle(0.2)
val b = Square(1.3)
val c = Rectangle(4.0,2.0)
fun area (Circle(r)) = 3.14 * r * r
| area (Square(s)) = s * s
| area (Rectangle(b,h)) = b * h
Does this help to explain a little about sml?
In SML you can define "abstractions" by means of using a combination of things like algebraic data types and signatures.
Algebraic data types let you define new types specific to the problem domain and signatures let you provide functionality/behavior around those types and provide a convenient way to implement information hiding and extensibility and reusability.
Combining this things you can create "abstractions" whose implementation details are hidden from you and that you simply understand through their public interfaces (whatever the signature expose).
I am reading the book by Jason, and face the following code.
let x = ref None;;
let one_shot y =
match !x with
None ->
x := Some y;
y
| Some z -> z;;
I do not understand the meaning of Some and None here.
None is something like is not set or null. if a value matches None, this value is not set.
Some is something like is set with something or not null. if a value matches Some z, this value has a value z.
here, the function one_shot looks !x (the variable in address x). if its None then sets with y and returns y and if is Some z then returns z
They are constructors of a built-in OCaml datatype, that you could have defined yourself as such:
type 'a option =
| None
| Some of 'a
This means that None if of type 'a option for any 'a, and, for example, Some 3 is an int option.
Those are constructors for the built-in option type, defined as follows:
type 'a option = None | Some of 'a
It's a generally useful sum type for representing an optional value, used as such in the example shown in your question.
Worth noting here, it's a built-in type (rather than provided in the Pervasives module) because it's used for inference of the types of functions with optional arguments.
For example, consider the following:
let f ?x () =
match x with
| Some x -> x
| None -> 0
This function has the following type:
val f: ?x:int -> unit -> int