Tokenize string with parameterised delimiter - sml

I need to tokenize string to list of words in Standard ML based on a delimeter which is to be passed as a function parameter. This is the code I have so far:
val splitter = String.token(fn (c:string,x:char) => c=x);
I tried this but i know its wrong .Please help me to modify it.

the type of c is string while the type of x is char. They are not comparable. You can convert x to string with Char.toString.
splitter = String.token(fn (c:string,x:char) => c=Char.toString x);

There is no standard library function called String.token, but maybe you mean String.tokens:
- String.tokens;
> val it = fn : (char -> bool) -> string -> string list
You're not saying if your separator is a string or a char, but assuming it's a char,
fun splitter sep s = String.tokens (fn c => c = sep) s
You could also define it as such,
fun curry f a b = f (a, b)
val splitter = String.tokens o curry op=

Related

Turning list of integers into string in OCaml

How could I turn a list of integers, such as [1;2;3], into a single string "123" using fold?
Right now, I think I'm doing:
let int_list_to_string (s : int list) : string =
fold (fun s combine -> combine + .... ) ""
or something along these lines, where .... could be something similar to String.length (which I used in a different fold problem to count characters in a string) but I don't know if this is even remotely correct.
Thank you!
Your basic layout looks right to me. Many things need to be fixed up. Here are a few:
You have to pick a specific fold function to use, List.fold_left or List.fold_right.
The function to be folded takes two parameters. One is the accumulated result and the other is the next input from the list. The order depends on whether you use fold_left or fold_right. Your code sketch has two parameters but one of them is suspiciously named s. This will not be the same s as the input list. The names after fun are new parameter variables introduced at that point.
The OCaml operator for concatenating strings is ^, which is what you should use where you have + (possibly just a placeholder in your code).
You need to convert each int to a string before concatenating. There is a function named string_of_int that does this.
You have to apply the fold to a list. I.e., fold takes 3 arguments but you are supplying only 2 arguments in your code sketch.
Note that the fun needs to concatenate an acc and the next list-element with the ^ - operator. The accumulator of List.fold_left needs to be the same as the output type, so it has to be an empty string: "".
let int_list_to_string lst = List.fold_left (fun acc x -> acc ^ string_of_int x) "" lst
val int_list_to_string : int list -> string = <fun>
# int_list_to_string [1;2;3];;
- : string = "123"
One could also create more advanced strings, e.g. with the list-syntax:
let int_list_to_string_fancy lst =
"[" ^ ( List.fold_left( fun acc x -> acc ^ string_of_int x ^ ";" ) "" lst) ^ "]"
val int_list_to_string_fancy : int list -> string = <fun>
# int_list_to_string_fancy [1;2;3];;
- : string = "[1;2;3;]"

Create a list reading a file with SML

I'm trying to create a List reading a text file, for example I have a text file like this "1 5 12 9 2 6" and I want to create a list like this [1,5,12,9,2,6] using SML
You can divide this task into several sub-problems:
Reading a file into a string can be done with
type filepath = string
(* filepath -> string *)
fun readFile filePath =
let val fd = TextIO.openIn filePath
val s = TextIO.inputAll fd
val _ = TextIO.closeIn fd
in s end
See the TextIO library.
Converting a string into a list of strings separated by whitespace can be done with
(* string -> string list *)
fun split s =
String.tokens Char.isSpace s
See the String.tokens function.
Converting a list of strings into a list of integers can be done with
(* 'a option list -> 'a list option *)
fun sequence (SOME x :: rest) = Option.map (fn xs => x :: xs) (sequence rest)
| sequence (NONE :: _) = NONE
| sequence [] = SOME []
fun convert ss = sequence (List.map Int.fromString ss)
Since any one string-to-integer conversion with Int.fromString may fail and produce a NONE, List.map Int.fromString will produce an "int option list" rather than an "int list". This list of "int option" may be converted to an optional "int list", i.e., remove the SOME of all the "int option", but if there's a single NONE, the entire result is discarded and becomes NONE. This gives the final type "int list option" (either NONE or SOME [1,2,...]).
See the Option.map function which was useful for this kind of recursion.
Combining these,
(* filepath -> int list *)
fun readIntegers filePath =
convert (split (readFile filePath))
This approach does yield some potentially unwanted behavior:
Filesystem errors will make readIntegers throw an Io exception
The string ~5 inside the file will be interpreted as negative five
The string -5 will produce a failure (NONE)
The string 123a will produce the number 123 (Int.toString is a bit too forgiving)
You may want to address those.

right-hand-side of clause doesn't agree with function result type

Write a function remove_option, which takes a string and a string list. Return NONE if the string is not in the list, else return SOME xs where xs is identical to the argument list except the string is not in it. You may assume the string is in the list at most once. Use same_string, provided to you, to compare strings. Sample solution is around 8 lines.
The function type should be fn : string * string list -> string list option.Here is my code
fun same_string(s1 : string, s2 : string) =
s1 = s2
fun remove_option (str: string ,str_list : string list) =
case str_list of
[] => NONE
| x::xs => if same_string(x,str)
then SOME xs
else x :: remove_option( str,xs)
and the error report
hw2provided.sml:10.5-15.37 Error: right-hand-side of clause doesn't agree with f
unction result type [tycon mismatch]
expression: _ option
result type: string list
in declaration:
remove_option =
(fn (<pat> : string,<pat> : string list) =>
(case str_list
of <pat> => <exp>
| <pat> => <exp>))
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:292.17-292.20
So where is the bug ?
The problem is that you want to return a string list option but the line
else x :: remove_option( str,xs)
makes it seem that you want to return a string list
What you need to do with the return value of remove_option( str,xs) is
1) decide what to do if it is NONE
2) extract the string list strings (or whatever you want to call it) if it is of the form SOME strings, tack x onto the front of the list, and repackage it with SOME before returning it.
You seem comfortable with the use of case, so you could use it here.
Since John showed where the bug is, here are some extra comments:
Since the function same_string is not injected, it is superfluous. You might as well use =.
Recursive functions that return 'a option are kind of tricky, since you need to unpack the result:
fun remove_option (s1, []) = NONE
| remove_option (s1, s2::ss) =
if s1 = s2
then SOME ss
else case remove_option (s1, ss) of
NONE => NONE
| SOME ss' => SOME (s2::ss')
Generally, when you see the pattern
case x_opt of
NONE => NONE
| SOME x => SOME (f x))
this can be refactored into using e.g. Option.map : ('a -> 'b) -> 'a option -> 'b option:
Option.map f x_opt
In this case,
fun curry f x y = f (x, y)
fun remove_option (s1, []) = NONE
| remove_option (s1, s2::ss) =
if s1 = s2
then SOME ss
else Option.map (curry op:: s2) (remove_option (s1, ss))
where curry op:: s2, the function that puts s2 in front of a list.

How to convert char list to string in OCaml?

I have a char list ['a';'b';'c']
How do I convert this to the string "abc"?
thanks x
You can create a string of a length, equal to the length of the list, and then fold over the list, with a counter and initialize the string with the contents of the list... But, since OCaml 4.02, the string type started to shift in the direction of immutability (and became immutable in 4.06), you should start to treat strings, as an immutable data structure. So, let's try another solution. There is the Buffer module that is use specifically for the string building:
# let buf = Buffer.create 16;;
val buf : Buffer.t = <abstr>
# List.iter (Buffer.add_char buf) ['a'; 'b'; 'c'];;
- : unit = ()
# Buffer.contents buf;;
- : string = "abc"
Or, as a function:
let string_of_chars chars =
let buf = Buffer.create 16 in
List.iter (Buffer.add_char buf) chars;
Buffer.contents buf
let cl2s cl = String.concat "" (List.map (String.make 1) cl)
Since OCaml 4.07, you can use sequences to easily do that.
let l = ['a';'b';'c'] in
let s = String.of_seq (List.to_seq l) in
assert ( s = "abc" )
Commonly used Base library also offers Base.String.of_char_list

convert a few 2-tuples to a list of lists

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.