First of all, I have those types :
type position = float * float
type node = position
To build my Map I've written those modules :
module MyMap =
struct
type t = Graph.node
let compare (a1,b1) (a2,b2) =
if a1 > a2 then 1
else if a1 < a2 then -1
else if b1 > b2 then 1
else if b1 < b2 then -1
else 0
end
module DistMap = Map.Make(MyMap)
In my case, I'll have a previousMap that has type val previousMap : (float * float) DistMap.t = <abstr>
It contains nodes as key, and values.
Let's say it is built like this :
DistMap.bindings prevMap;;
- : (node * (float * float)) list =
[((1., 1.), (2., 2.));
((2., 2.), (3., 3.));
((3., 3.), (4., 4.));
((4., 4.), (5., 5.))]
It means that (2.,2.) is the predecessor node of (1.,1.) in a graph.
What I am aiming for is to build the list that represent the path from a source node to a target node.
For example, if I had :
let build_path prevMap source target
The expected output using the previousMap would be a node (or float * float) list like this :
build_path previousMap (1.,1.) (5.,5.) -> [(1.,1.);(2.,2.);(3.,3.);(4.,4.);(5.,5.)]
So far my attempts consisted in trying to use the fold and iter function on the previousMap but they were inconclusive.
Update :
Here's an attempt I think could be close to what I want to achieve :
let build_list map source target =
let rec build_aux acc map source x =
if ((DistMap.find x map)) = source then source::acc
else build_aux (DistMap.find x map)::acc source (DistMap.find x map)
in build_aux [] map source target
However I get this error output :
356 | else build_aux (DistMap.find x map)::acc source (DistMap.find x map)
^^^^^^^^^^^^^^^^^^^^
Error: This expression has type 'a but an expression was expected of type
'a list
The type variable 'a occurs inside 'a list
Update 2 :
The issue has been solved, however the function isn't behaving as expected. Basically this is the pseudo-code I'd like to implement :
How could I proceed to build such a list?
Thanks.
The problem with fold and iter is that they process nodes in an order that they determine themselves. In essence the order is based on the shape of the map, which is determined by the keys. You want to process the nodes of the map in an order determined by the values in the map.
I'm pretty sure the only way to proceed is to write your own special-purpose recursive function.
Update
In the latest code you have this expression:
build_aux (DistMap.find x map)::acc source (DistMap.find x map)
The operator precedence in OCaml that binds function arguments to functions is very tight, so this gets parsed like this:
(build_aux (DistMap.find x map)) :: (acc source (DistMap.find x map))
You need parentheses around this subexpression:
((DistMap.find x map)::acc)
Related
I am a beginner in OCaml and I'm trying to understand functors, I'm developing a "general sort function" with functors that can takes array, list, string and return an ordered list, array, string.
Can someone help me with this?
I've done this
module type Comparable= sig
type t
val compare : t -> t -> int
val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
end;;
module Make_sort(S: Comparable)= struct
type t= S.t
type et= S.t list
let order t= function
|[] -> 0
|a::b -> S.fold_left (S.compare (a t)(b t)) ;;
end;;
First of all, I think that your intuition is correct but there is small confusion between the value level and the type level, ie: S.compare (a t)(b t) this expression is not valid (a and b) must be functions, this why I think that you try to give the sense of 'a t.
But, I understand what you try to do, so here is a small primer on functor (function from module to module), using a small subset of your example.
First, in order to sort we need to define how to order
Exactly as you did, we can start with a signature (COMPARABLE) which handle the "notion of comparison". For example:
module type COMPARABLE = sig
(** something which is comparable. *)
type t
(** [compare x y] returns 1 if x > y, 0 if x = 0 and -1 if x < 0 *)
val compare : t -> t -> int
end
With this signature, it is easy to define module which are comparable, for example, for Int:
module Int_comparable :
COMPARABLE with type t = int =
struct
type t = int
let compare x y =
if x > y then 1
else if x = 0 then 0
else -1
end
Note that module are candidate for a signature only if the module match the signature so de anotation : COMPARABLE with type t = int is not very necessary. And, since Int (the module from the stdlib) already implement compare and a type t, it is not necessary to define it. You can just pass Int when you need a comparable.
Now, we can define somethign "sortable"
In this very small example, something which is comparable seems to be sortable. In other words, if I have a COMPARABLE, I can sort. This relation (If I have X, I can have Y) seems quite suitable for using a functor (so, I give you a COMPARABLE and you give me something sortable). Here is a proposition:
module Sortable (C : COMPARABLE) : sig
(** if something is comparable, it is sortable. *)
type t = C.t
(** [max_of x y] returns the greater between x and y. *)
val max_of : t -> t -> t
(** [min_of x y] returns the lower between x and y. *)
val min_of : t -> t -> t
(** [sort x y] returns an ordered tuple [(max_of x y, min_of x y)]. *)
val sort : t -> t -> (t * t)
end = struct
type t = C.t
let max_of x y =
let value = C.compare x y in
if value > 0 then x
else y
let min_of x y =
let value = C.compare x y in
if value < 0 then x
else y
let sort x y =
if (C.compare x y) >= 0 then (y, x) else (x, y)
end
It is probably possible to add more helpers in the module, but I'll keep the implementation as simple as possible. So now, if I want have sortable capabilities for Int.t I can just use the module Int (from stdlib: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Int.html) which has a type t and compare like this
module Sortable_int = Sortable (Int)
Now, you have the basis. For traversing using Sort, you can implement a signature (Foldable for example) and I think you have all the bricks in your hands to generalize the logic of sorting collections (modulo a little algorithmic!)
I have a node type like the following :
type position = float * float
type node = position
I created those modules for the Map :
module MyMap =
struct
type t = node
let compare (a1,b1) (a2,b2) =
if a1 > a2 then 1
else if a1 < a2 then -1
else if b1 > b2 then 1
else if b1 < b2 then -1
else 0
end
module DistMap = Map.Make(MyMap)
I have written this function to add elements to my map.
let init_dist nodes source =
let testMap = DistMap.empty in
let rec init_dist_aux nodes map source =
match nodes with
| [] -> map
| x::tl -> if x = source then map = DistMap.add x 0. map else map = DistMap.add x max_float map;
init_dist_aux tl map source
in init_dist_aux nodes testMap source
The output was :
Characters 160-186:
Warning 10: this expression should have type unit.
val init_dist : node list -> node -> float DistMap.t = <fun>
I tried this :
let initMap = init_dist nodes (4.67521849144109414,6.85329046476252568);;
However init_dist has type unit, so I was unable to create the Map.
My goal is to be able to use this function to build a map.
The error lays in the code below :
match nodes with
| [] -> map
| x::tl -> if x = source then map = DistMap.add x 0. map else map = DistMap.add x max_float map;
init_dist_aux tl map source
Around the 2 pieces of code :
map = DistMap.add...
This is a comparison (and so a boolean) not an assignement as you might wish to implement.
You have to first evaluate map vialet and then process init_dist_aux with new map. Or, since the only difference is the 2nd value (0. or max_float), you can first evaluate this second argument, then process the whole thing as below:
match nodes with
| [] -> map
| x::tl -> let v = if (x = source)
then 0.
else max_float
in
init_dist_aux tl (Dist.add x v map) source
I have three type :
type position = float * float
type node = position
type edge = node * node * float
And I'd like to make a list of edge by using a list of node by doing this :
let create_type_list nodes_list =
let rec create_type_list_aux nodes =
match nodes with
| [] -> []
| x::y::l -> Some (x,y, dist2 x y) # create_type_list_aux l
in create_type_list_aux nodes_list
dist2 is just a function that calculates the distance between two nodes.
I'm left wondering why such a function can't work and how I could be able to reach my goal of creating a list of type. I have the following error :
Error: This variant expression is expected to have type 'a list
The constructor Some does not belong to type list
Thanks
The expression you're using to build up the list is presumably this:
Some (x,y, dist2 x y) :: create_type_list_aux l
Indeed this adds an element to the front of the list of type (position * position * float) option. However, the type position is the same as the type node. So this is also type (node * node * float) option. This, in turn is the same as edge option. So your only problem is that you're adding an edge option to your list rather than an edge. You might try using this expression instead:
(x, y, dist2 x y) :: create_type_list_aux l
The only difference is that I removed Some, which is a constructor of the option type.
this is a question about ocaml lists and tuples. I have some 2-tuples of numbers (either integers or floats) and I want to convert it to a list of lists (with 2 elements). Assuming that I have defined a num type Int of int | Float of float, the conversion should give the following:
((1,1.0),(0.4,1),(0,0)) => [[Int 1;Float 1.0];[Float 0.4; Int 1];[Int 0;Int 0]]
or more precisely
let a = (1,1.0) and b = (0.4,1) and c = (0,0) in
myconversion (a,b,c) ;;
=> [[Int 1;Float 1.0];[Float 0.4; Int 1];[Int 0;Int 0]]
the point being the values a, b, c... are defined in several places in the source files (by people who use different signatures for their tuples).
The difficulty here is that I don't know the types of the elements of the 2-tuples (int or float, that varies depending on the tuple).
Your input data can't be represented in OCaml as you describe it. OCaml is strongly typed. For example, your example input list is an invalid value in OCaml:
# [(1,1.0);(0.4,1);(0,0)];;
Error: This expression has type float but an expression was expected of type
int
So what you describe as the essence of your problem (not knowing the types) is in fact not possible. You'll have to use some other method of representing the input. For example, you could just use floats for everything. Or you could use pairs of strings.
Update
The answer for the rewritten question is the same. In OCaml it's not possible not to know the type of something statically; i.e., at the time you're writing the program (unless it can be any type at all). It's not possible (or necessary) to query the type of something at runtime. So your question doesn't have an answer (at least as far as I can see).
For OCaml, you have to think with the type system rather than against it. After a while you start to really like it (or at least that's how it worked for me). I'd start by writing down the type you want your function myconverstion to have.
Update 2
I'll repeat my advice to treat your inputs as strings. Assuming you've parsed your input up into pairs of strings, here's some code that does what you want:
let myconversion coords =
let c1 s =
if String.contains s '.' then
Float (float_of_string s)
else
Int (int_of_string s)
in
let cp (a, b) = [c1 a; c1 b] in
List.map cp coords
Here's how it works for your input (reinterpreted as strings):
# myconversion [("1", "1.0"); ("0.4", "1"); ("0", "0")];;
- : fi list list = [[Int 1; Float 1.]; [Float 0.4; Int 1]; [Int 0; Int 0]]
Update 3
Here's some (crude) code that parses a file of numbers into coordinates represented as pairs of strings. It should work as long as the tuples in the input are well formed.
let coords fname =
let ic = open_in fname in
let len = in_channel_length ic in
let buf = Buffer.create 128 in
let () = Buffer.add_channel buf ic len in
let () = close_in ic in
let s = Buffer.contents buf in
let nums = Str.(split (regexp "[^0-9.]+") s) in
let rec mkcoords sofar = function
| [] | [_] -> List.rev sofar
| a :: b :: rest -> mkcoords ((a, b) :: sofar) rest
in
mkcoords [] nums
There are two distinct problems in your setup:
you don't know the type of the tuples parameters
you want to pass them as a single n-ary tuple
For problem 2, you would have to write a function for that type specifically, whereas you could mimic a type level list type by nesting couple of tuples:
myconversion a,(b,c) ;;
The reason is that with that setup, you could write a recursive polymorphic function on the type level list:
val myconversion : type a b. (a,b) -> num list
There would still be a problem on the last element though.
So, assuming that you could pass a sequence to your conversion function, and have it process elements of that sequence one by one, you would still need to find a way of selecting the proper function of pair conversion from the tuple type: that's basically ad-hoc polymorphism, ie. you would need to be able to overload a function on its parameters' types(1). Unfortunately, OCaml doesn't support that out of the box.
One possibility would be perhaps (I have no experience doing that) to implement an extension which would extract the type information of a given expression, and generate the correct code to process it in your own code.
A flexible technique consists in having that extension generate an algebraic description of the tuples types, and use that description as an equality witness in the code which will process the tuples:
type _ w =
| U : (unit * unit) w
| IF : 'a w -> ((int * float) * 'a) w
| FI : 'a w -> ((float * int) * 'a) w
(* other constructors if necessary *)
(* data *)
let a = 1,1.0
let b = 2.0, 2
let c = 3.0, 3
let d = 4, 4.0
let l = a,(b, (c,(d,((),()))))
(* witness *)
let w = IF (FI (FI (IF U)))
(* the type parameter of w should be the same as l type *)
let rec conv : type a b. (a * b) w -> (a * b) -> num list = fun w (x, xs) ->
match w with
U -> []
| IF w' -> let i,f = x in (Int I)::(Float f)::(conv w' xs)
(* etc *)
Here, we encode the type level nil list as (unit * unit) w.
A coalgebraic approach would require to register function overloads to the conversion function polymorphic signature within the extension, and let it pick the right one from the function overload dictionary.
There's a discussion on that topic on the LtU site.
Thanks to everybody who answered. I finally found a solution, using a bit of magic:
# type num = Int of int | Float of float;;
# let to_num x = if Obj.is_int (Obj.repr x) then
Int (Obj.magic (Obj.repr x) : int)
else
Float ((Obj.magic (Obj.repr x) : float));;
# let pair_to_num (a,b) = [to_num a; to_num b];;
# let myconversion (a,b,c) = [pair_to_num a; pair_to_num b; pair_to_num c];;
and the test:
# myconversion ((1,1.0),(0.4,1),(0,0));;
- : num list list = [[Int 1; Float 1.]; [Float 0.4; Int 1]; [Int 0; Int 0]]
# myconversion ((0,0),(1,1.0),(0.4,1));;
- : num list list = [[Int 0; Int 0]; [Int 1; Float 1.]; [Float 0.4; Int 1]]
Magic, the order does not matter and the type is recorded! I can then follow didier's idea to get rid of the pair of superfluous parentheses.
I am new to OCaml and I am trying to write a function to do this:
(4,a)(1,b)(2,c)(2,a)(1,d)(4,e) --> ((4 a) b (2 c) (2 a) d (4 e))
and this is what I wrote:
let rec transform l =
match l with
| (x,y)::t -> if x = 1 then y::transform(t) else [x; y]::transform(t)
| [] -> []
I put it in the ocaml interpreter but error generated like this:
Error: This expression has type int list
but an expression was expected of type int
Could anyone give some help?
Your example transformation doesn't make it clear what the types of the values are supposed to be.
If they're supposed to be lists, the result isn't a possible list in OCaml. OCaml lists are homogeneous, i.e., all the elements of the list have the same type. This is (in essence) what the compiler is complaining about.
Update
Looking at your code, the problem is here:
if x = 1
then y :: transform (t)
else [x; y] :: transform t
Let's say the type of y is 'a. The expression after then seems to have type 'a list, because y is the head of the list. The expression after else seems to have type 'a list list, because a list containing y is the head of the list. These aren't the same type.
The main problem is to decide how to represent something as either (4 a) or b. The usual OCaml way to represent something-or-something-else is variants, so let's define one of those:
type 'a element =
| Single of 'a
| Count of int * 'a
let rec transform = function
| [] -> []
| (x,y)::t ->
if x = 1 then Single y::transform t
else Count (x, y)::transform t
Note that this won't print in quite the way you want, unless you register a printer with the toplevel.
Or better:
let compact (x, y) =
if x = 1 then Single y else Count (x, y)
let transform list = List.map compact list