unfolding lists in ML - sml

hello everyone I'm trying to write function which can unfold int in the list from any depth, for example if I have following bigList: [12, [34], [11,[1]]] I want to receive
[(1,12),(2,34),(3,11),(4,1)]
first element in tuple is the depth and the second is the number
I wrote this code:
datatype 'a bigList = Empty of unit
| Element of 'a
| List of 'a bigList list;
local
fun unfolder( Empty , n ) = []
| unfolder( (Element l)::ls, n ) = (n, l)::unfolder( ls, n )
| unfolder( (List l)::ls, n) = unfolder( l, n + 1)::unfolder(ls, n)
in
fun flat list = unfolder(list, 1)
end;
every time I receive the following error:
Standard ML of New Jersey v110.71 [built: Thu Sep 17 08:50:14 2009]
- datatype 'a bigList = Element of 'a | Empty of unit | List of 'a bigList list
stdIn:9.5-11.69 Error: data constructor Empty used without argument in pattern
stdIn:11.33-11.69 Error: operator and operand don't agree [tycon mismatch]
operator domain: (int * 'Z) list * (int * 'Z) list list
operand: (int * 'Z) list * (int * 'Z) list
in expression:
unfolder (l,n + 1) :: unfolder (ls,n)
-
thanks in advance for any help

data constructor Empty used without argument in pattern
You defined Empty as Empty of unit, which means you need to use it as Empty (), which is pretty pointless. To use it as just Empty, you need to define it as Empty without the of unit.
unfolder (l,n + 1) :: unfolder (ls,n)
The type of :: is 'a * ['a] -> ['a], which means that the left operand must be a single element and the right operand a list. In the above both operands are a list, so you get a type error.
To concatenate two lists use the # operator, not ::.

Related

Ocaml Error with returning a List option type

I've been struggling to get this code to return a ((int * int) list) option.
It takes two lists of integers and combines them into a list of pairs of ints.
let rec safe_zip (ls1: int list) (ls2: int list) : ((int * int) list) option =
match (ls1, ls2) with
| ([],[]) -> None
| ([],_) -> None
| (_,[]) -> None
| (h1::t1, h2::t2) ->
Some (List.append [(h1,h2)] (safe_zip (t1 t2)))
However the (safe_zip (t1 t1)) is showing an error saying
This expression has type int list -> (int * int) list option
but an expression was expected of type (int * int) list`
How can I fix this error?
Well, this call:
safe_zip (t1 t2)
is passing one parameter to safe_zip. But safe_zip takes two parameters.
Function calls in OCaml are denoted just by putting expressions next to each other. The parameters aren't parenthesized.
For example, to append two lists:
List.append [1; 2] [3; 4]
Note there are no parentheses around the two parameters.
Second, note that safe_zip doesn't return a list. It returns a list option. So you can't just append its result to another list.

Int lists in functions

Does this function take two int lists "x and y" and return an int list of y-x?
let rec fun4 (l: int list) :int list =
begin match l with | [] -> []
| [_] -> []
| x::y::rest -> (y-x)::(fun4 (y::rest))
end
A list is defined as a recursive type:
type 'a list =
| [] of 'a list (* the empty case *)
| ( :: ) of 'a * 'a list
So you basically have two constructors: [] which is the empty list, and x :: other_list which is a list with x as head and other_list as tail. The use of these constructors makes it easy to define a list: [0; 1; 2; 3] is exactly the same of 0 :: 1 :: 2 :: 3 and of (::) (0, (::) (1, (::) (2, (::) (3, [])))) (which is not very pleasant to read).
Recursive algebraic types, here we have the conjunction of sums ([] and (::)) and products (('a * 'a list)), combined with pattern matching make it possible to describe all sorts of common data structures, as well as their functions for consuming, modifying etc.
In your example, you use pattern matching to deconstruct the list:
let rec fun4 my_list =
match my_list with
(* if my list is empty, I can't process the function so
I return the empty list *)
| [] -> []
(* if my list my list has only one element, I can't process the function
so, like in the previouse case, I return the empty list *)
| [ _ ] -> []
(* Here is the last case of the function, If I almost have two elements in the
list. Remember that empty list is also a list ! *)
| x :: y :: rest -> (y - x) :: (fun4 (y :: rest))
As you can see, Recursives Algebraic data types coupled with pattern matching are a powerful for describing data structures (like list but also many others) and for writing function that use those data structures.

ocaml 'a list list function tuples

let sample_table4 = [
[["11"];["21"];["31"];["41"]];
[["12"];["22"];["32"]];
[["13"];["23"]];
[["14"]]];;
This is where I'm stuck with writing a function to get one of these numbers
let tgvc (pos, table) =
match pos with
|[] -> []
|i::[j] -> List.nth (List.nth table (j-1)) (i-1)
|i::_ -> []
;;
val tgvc : int list * 'a list list list -> 'a list = <fun>
I'm supposed to get this signature
tgvc ([3;2],sample_table4);;
val tgvc : int list * ’a list list -> ’a = <fun>
-: string list = ["32"]
What's missing in the function?
I'm sure it has to be recursive now.
Even though it computes the right answer, it's not the right method. The ->[ ] is what's getting me
let rec tgvc (pos, table) = function
|_,[] -> []
|[i;1], h::_ -> List.nth h (i-1)
|[i;j], _::t -> tgvc ([i;j-1], t)
|_ -> []
|[i;j], _::t -> tgvc ([i;j-1], t)
^^^^^^^^^^^^^^^^^
Error: This expression has type int list * 'a list list list -> 'a list
but an expression was expected of type 'a list
What's missing in the function?
A lot of things. Your function simply returns one of many lists of initial input. You don't even use i indice.
I suggest you to think what your function need to do for the given input:
[i; 1], h::_ - you are "in front" of the desirable list
[i; j], _::t - not desirable list yet (some recursion maybe?)
_, [] - empty table
_ - everything else
Edit
You have two problems with your last implementation. First of all in your first and last branches you return [], I guess you would like to exit with an error, so you can throw an exception (via failwith for example). The second problem is actually in the first line: get_table_values_cell (pos, table) = function, it means that you define get_table_values_cell as function with two arguments, you give one explicitly ((pos, table)) and the second is introduced by function keyword. So all you need is to pick only one: get_table_values_cell = function

OCaml - why is my function of type 'a list list -> ... rather than 'a list?

let rec slice l i k = match l with
h::t -> if (k == 0) then h
else if (i == 0) then h # (slice t 0 (k-1))
else slice t (i-1) (k-1);;
When I enter slice [1; 2; 3; 4] 1 2;; I get:
Error: This expression has type int but an expression was expected of type 'a list
however if I enter slice [[1]; [2]; [3]; [4]] 1 2;; it works as intended. I don't understand why OCaml thinks l is a list of lists of 'a, and not just a standard list of 'a?
I see two problems. In your first case you return h. But you should be returning a list, and h is the first element of your list.
In your second case you use the # operator, which expects a list on both sides. But h is the first element of your list, not a list. You can fix this by using :: instead of #.
Other problems:
I don't see a place where you handle an empty list l.
You should use = rather than ==. The == operator in OCaml is for very special purposes only. For day-to-day equality comparisons you want to use =.

How can I match an empty list of tuples?

The following function gives a compilation error at the point I try to match an empty list:
let rec tuplesToList (acc: int list) (remaining: int*int list) =
match remaining with
| [] -> acc
| (a, b) :: tail -> tuplesToList (a :: b :: acc)
The error is:
This expression was expected to have type int * int list but here has type 'a list
This works fine when remaining is a simple list of ints rather than tuples. How can I match an empty list of tuples?
[] is just fine to match an empty list of tuples. But according to your type annotation, remaining is not a list of tuples, it's a tuple containing an int and an int list. A list of tuples would be (int*int) list. int * int list is parsed as int * (int list), not (int * int) list.
If you fix the type, your code should work fine.
In addition to sepp2k's observation, you've also forgotten the second parameter (tail) in the recursive call. Also, your code works fine without any type annotations whatsoever:
let rec tuplesToList acc remaining =
match remaining with
| [] -> List.rev acc //reverse to preserve original order
| (a, b) :: tail -> tuplesToList (a :: b :: acc) tail