I'm trying to create a function that has the type:
unit -> (int list * int list * int list)
But I was wondering, unit is an empty type (has no value), so how would it be possible to do something with it and return 3 int lists?
Thanks
The type unit is not empty.
It has one value which is spelled () and is usually called "unit", like its type.
(One meaning of the word "unit" is "a single thing".)
Example:
- ();
val it = () : unit
- val you_knit = ();
val you_knit = () : unit
- fun foo () = ([1], [2], [3]);
val foo = fn : unit -> int list * int list * int list
- foo ();
val it = ([1],[2],[3]) : int list * int list * int list
- foo you_knit;
val it = ([1],[2],[3]) : int list * int list * int list
(Note that () is not an empty parameter list; ML doesn't have parameter lists.)
Strictly speaking, the above definition pattern-matches on the value ().
Without pattern matching, it could look like this:
- fun bar (x : unit) = ([1], [2], [3]);
val bar = fn : unit -> int list * int list * int list
- bar ();
val it = ([1],[2],[3]) : int list * int list * int list
In SML type unit often represents an input/output action or more generally something which involves side effects. A somewhat realistic example of a function of the sort you are looking for would be one which returns 3 randomly generated lists. Another example would be one which pulls numbers from standard input something like:
open TextIO
fun split s = String.tokens (fn c => c = #",") s
fun toInt s = valOf (Int.fromString s)
fun toIntList line = map toInt (split line)
fun getInts prompt =
(
print prompt;
case inputLine(stdIn) of
SOME line => toIntList line |
NONE => []
)
fun getLists() =
let
val prompt = "Enter integers, separated by a comma: "
in
(getInts prompt, getInts prompt, getInts prompt)
end
The type of getLists is
val getLists = fn : unit -> int list * int list * int list
a typical "run" of getLists:
- getLists();
Enter integers, separated by a comma: 1,2,3
Enter integers, separated by a comma: 4,5,6
Enter integers, separated by a comma: 7,8,9
val it = ([1,2,3],[4,5,6],[7,8,9]) : int list * int list * int list
Related
I have a .txt file that contains this:
d3%~19^fgh54 78nm,.j
1.2k~789bv
This is the code that I have:
fun parse(L) =
let
val infile = TextIO.openIn(L)
fun read(infile) =
if TextIO.endOfStream(infile) then " " else (valOf(TextIO.inputLine(infile))) ^ read(infile);
fun split(S) = explode(S)
in
split(read(infile))
end;
This is the output I get:
[#"d",#"3",#"%",#"~",#"1",#"9",#"^",#"f",#"g",#"h",#"5",#"4",#" ",#"7",#"8",
#"n",...] : char list
I cannot figure out why the explode will not turn the whole string it is given into a char list.
The top-level printer in SML/NJ has limits for how much of data structures it prints.
You can adjust (among other things) the displayed length of lists and strings, and the depth of recursive structures with the Control.Print structure.
Example:
- Control.Print.printLength;
val it = ref 16 : int ref
- val stuff = [1,2,3,4,5,6,7,8,9,10];
val stuff = [1,2,3,4,5,6,7,8,9,10] : int list
- Control.Print.printLength := 4;
val it = () : unit
- stuff;
val it = [1,2,3,4,...] : int list
- Control.Print.printDepth;
val it = ref 5 : int ref
- val deep = [[[[[[[[]]]]]]]];
val deep = [[[[[#]]]]] : 'a list list list list list list list list
- Control.Print.printDepth := 10;
val it = () : unit
- deep;
val it = [[[[[[[[]]]]]]]] : 'a list list list list list list list list
If you want to see everything regardless of size, you need to define and use functions that print the way you like.
New to Ocaml so asking a very basic question.
If I have a type say type foobar = foo * bar and a variable a of type foobar. Is it possible to get just the value of foo from a with a method? Is there any other way than pattern matching? Also, in this case how would you apply pattern matching? Since the type declared is not declared as type foobar = | Foobar of foo * bar?
You can match against a pair like this:
# type intfloat = int * float;;
type intfloat = int * float
# let x : intfloat = (3, 5.5);;
val x : intfloat = (3, 5.5)
# let (int_part, _) = x in int_part;;
- : int = 3
# let (_, float_part) = x in float_part;;
- : float = 5.5
There is a function (not a method) fst that returns the first element of a pair.
# fst x;;
- : int = 3
However, the definition of fst necessarily uses pattern matching:
let fst (a, b) = a
In this definition, the construct (a, b) is a pattern that matches a pair.
Pattern matching is an essential part of OCaml, not just a fancy optional feature.
I'm working on an assignment and was given the following function:
fun label (lb,ub) =
let val s = callcc (fn k =>let fun branch c = if (c < ub)
then (pushCP (k,branch,c+1);c)
else ub
in (pushCP(k,branch,lb+1);lb)
end)
in {value=s,dom=(lb,ub)}
end;
If you put a lower and upper bound of let's say 1 and 3into this function it would print
val it = {dom=(1,3), value=1}
What I am trying to figure out is if it is at all possible to get the value. In my notes it says two possible ways of doing this would be through #value(x) or by doing val {value=a,...} = x, but I get errors both ways with this.
Any clue what I am doing wrong?
It isn't clear what you are doing wrong since you haven't reproduced what you actually tried, but your notes are correct:
- val x = {dom=(1,3), value=1};
val x = {dom=(1,3),value=1} : {dom:int * int, value:int}
The first method is to use #value to extract the value field and #dom to extract the dom field:
- #value x;
val it = 1 : int
- #dom x;
val it = (1,3) : int * int
The second method is to use pattern matching. You can extract individual fields:
- val {value = a,...} = x;
val a = 1 : int
Or you can extract both fields at once:
- val {dom = a, value = b} = x;
val a = (1,3) : int * int
val b = 1 : int
In order for the above to work, x needs to be bound to the value. Perhaps you are trying to use this with an x which hasn't been given a val binding. You would need to have something like this:
val x = label(1,3)
I don't have all the relevant code so I can't test. If the above isn't enough to answer your question, you need to provide more details.
for example if I create a new type
type map = int * string;
val a = (1,"a") : int * string;
and then I want to get the inner "a" string from variable a, how can I get that?
I have tried a[1], a[2], a(2) and they don't work...
You can use the #n operator to get the n-th element of any tuple. In the REPL:
- #1("one", "two");
val it = "one" : string
- #2("one", "two");
val it = "two" : string
Since the new type is just a two-tuple, you may use pattern-matching, just as you would for other types:
- val a = (1, "a");
val a = (1,"a") : int * string
- case a of (_, str) => str;
val it = "a" : string
- (fn (_, str) => str) a;
val it = "a" : string
If this becomes a common operation, you might consider using a utility function:
fun unpackStr (_, str) = str;
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.