This question already has answers here:
how to populate existing list / array
(2 answers)
Closed 4 years ago.
How to append an element at the end of a list in ReasonML (the equivalent of Array.concat in JavaScript)?
While Neil's answer is technically correct, it glosses over some details that you might want to consider before reaching for append; specifically that while adding an element to the beginning of a list is very cheap, adding an element to the end is very expensive.
To understand why, let's look at how a list is defined and constructed. The (conceptual) definition of a list is:
// Reason
type list('a) = Cons('a, list('a)) | Nil;
(* OCaml *)
type 'a list = Cons of 'a* 'a list | Nil
where Nil represents the end of a list (and by itself an empty list) and Cons represents a node in the list, containing an element of type 'a and a pointer to the rest of the list (list('a), OCaml: 'a list).
If we took away all the syntax sugar and every helper function, you would have to construct a list like this:
// Reason
let myList = Cons(1, Cons(2, Cons(3, Nil)));
(* OCaml *)
let myList = Cons (1, Cons (2, Cons (3, Nil)))
To add an element to the head of this list then, we construct a node containing our new element and a pointer to the old list:
// Reason
let myBiggerList = Cons(0, myList);
(* OCaml *)
let myBiggerList = Cons (0, myList)
This is exactly the same as doing [0, ...myList] (OCaml: 0 :: myList). If myList could change we wouldn't be able to do this, of course, but we know it doesn't since lists are immutable. That makes this very cheap, and for the same reason it's just as cheap to pop the head off, which is why you'll usually see list processing functions implemented using recursion, like this:
// Reason
let rec map = f =>
fun | [] => []
| [x, ...xs] => [f(x), ...map(f, xs)];
(* OCaml *)
let rec map f = function
| [] -> []
| x::xs -> (f x) :: (map f xs)
Ok, so then why is it so expensive to add an element to the tail of the list? If you look back at myList, adding an element to the end means replacing the final Nil with, say, Cons(4, Nil). But then we need to replace Cons(3, ...) since that points to the old Nil, and Cons(2, ...) because it point to the old Cons(3, ...), and so on through the entire list. And you have to do that every time you add an element. That quickly adds up.
So what should you do instead?
If you're adding to the end and either just iterating through it or always taking elements off the end, like you often would in JavaScript, you cam most likely just reverse your logic. Instead of adding to and taking off the end, add to and take off the beginning.
If you actually need a FIFO data structure, where elements are inserted at one end and taken off at the other, consider using a Queue instead. In general, have a look at this comparison of the performance characteristics of the standard containers.
Or if this is all a bit much and you'd really just like to do it like you're used to from JavaScript, just use an array instead of a list. You'll find all the functions you're familiar with in the Js.Array module
You can use List.append or the # operator which is shorthand for List.append.
let lstA = [ 1 ];
let lstB = lstA # [ 2 ];
let lstC = List.append(lstB, [ 3 ]);
Here is the documentation for List methods: https://reasonml.github.io/api/List.html
See a playground link here: https://reasonml.github.io/en/try.html?reason=DYUwLgBMDOYIIQLwQNoQIwQLoG4BQokMYAQklLAgAKoQBM2+hFYAwuQDICWsAdAIYAHQSAB2AEwAUxEgBpaAZmwBKfEA
Related
I am trying to figure out is there anyway that i can use append to make the three lists of integer inside a list to become a list of a list of integers, for example
[[1];[2];[3]] -> [[1;2;3]]
[] -> [[]]
[[]] -> []
but i am not sure how loop really in OCaml.
and the below is what i have tried, but i dont think it work
let rec ls (l : 'a list list) =
match l with
| [] -> []
| x :: y -> l#y
i have tried to use # to do function, but i don't how to remove the bracket.
Note that in your attempt, you never use x which is the head of the list, and the function is not recursive. It never calls itself. Note that # is never necessary in this exercise, which is good because it leads to some ugly performance implications.
Consider that you can use pattern-matching to identify whether a list is empty or not, and to extract elements from the head and the tail of a list. What should the result of flattening an empty list be? An empty list.
let rec flatten =
function
| [] -> []
Now, if the first list in the list of lists is empty, it should be the result of flattening the tail. This seems pretty obvious so far.
let rec flatten =
function
| [] -> []
| []::tl -> flatten tl
Now, if it's not empty then we can cons the first element of the first list onto the result of flattening... I'll leave that as an exercise for you to fill in.
let rec flatten =
function
| [] -> []
| []::tl -> flatten tl
| (x::xs)::tl -> x :: flatten ...
Looping via recursion
While OCaml does have imperative loops, it is much more idiomatic, especially when dealing with lists, to loop via recursion.
In order to use recursion to loop, there must be at least one exit case where the function does not recursively call itself, but there must also be at least one case where it does, and that function call must in some way update the state being passed in so that it converges on the exit case.
If the exit case is passing in an empty list, the recursive calls must get closer to passing in an empty list on each call or the recursion will never end.
If you did want to append...
If you decided you do like #, and don't care about O(n^2) runtime complexity, you can use it with List.fold_left to readily accomplish this goal.
# List.fold_left (#) [] [[1;2]; [3;4]];;
- : int list = [1; 2; 3; 4]
This is equivalent to [] # [1;2] # [3;4].
I'm trying to pattern match on a list of pairs, where I'm trying to return a list from the list of pair, however I'm having trouble figuring out where to make the recursive call. Without the recursive call I have this:
let countriesInChart (cht: chart) =
match cht with
| [] -> []
| (x,y)::tt -> [x;y]
;;
But naturally this only applies to the first pair in the list and simply returns ["countryA"; "countryB"] without the rest of the list.
With the recursive call this simply only returns an empty list:
let rec countriesInChart (cht: chart) =
match cht with
| [] -> []
| (x,y)::tt -> [x;y]::countriesInChart tt
;;
How would I make the recursive call such that all the pairs in the list would return as a list?
You have this:
[x;y] :: countriesInChart tt
This says to add a new list of two elements onto the front of a list of lists.
I don't think you want a list of lists, you just want a list. So you shouldn't be making a list of two elements.
If x and y are the same type (as I suspect they are), what you probably want is this:
x :: y :: countriesInChart tt
This says to add both x and y individually to the front of the recursively generated list.
You can also write this, which is completely equivalent:
[x; y] # countriesInChart tt
However, this constructs a list of two elements only to throw it away. So it's a tiny bit of extra work for no benefit.
Its possible to create infinite, circular lists using let rec, without needing to resort to mutable references:
let rec xs = 1 :: 0 :: xs ;;
But can I use this same technique to write a function that receives a finite list and returns an infinite, circular version of it? I tried writing
let rec cycle xs =
let rec result = go xs and
go = function
| [] -> result
| (y::ys) -> y :: go ys in
result
;;
But got the following error
Error: This kind of expression is not allowed as right-hand side of `let rec'
Your code has two problems:
result = go xs is in illegal form for let rec
The function tries to create a loop by some computation, which falls into an infinite loop causing stack overflow.
The above code is rejected by the compiler because you cannot write an expression which may cause recursive computation in the right-hand side of let rec (see Limitations of let rec in OCaml).
Even if you fix the issue you still have a problem: cycle does not finish the job:
let rec cycle xs =
let rec go = function
| [] -> go xs
| y::ys -> y :: g ys
in
go xs;;
cycle [1;2];;
cycle [1;2] fails due to stack overflow.
In OCaml, let rec can define a looped structure only when its definition is "static" and does not perform any computation. let rec xs = 1 :: 0 :: xs is such an example: (::) is not a function but a constructor, which purely constructs the data structure. On the other hand, cycle performs some code execution to dynamically create a structure and it is infinite. I am afraid that you cannot write a function like cycle in OCaml.
If you want to introduce some loops in data like cycle in OCaml, what you can do is using lazy structure to prevent immediate infinite loops like Haskell's lazy list, or use mutation to make a loop by a substitution. OCaml's list is not lazy nor mutable, therefore you cannot write a function dynamically constructs looped lists.
If you do not mind using black magic, you could try this code:
let cycle l =
if l = [] then invalid_arg "cycle" else
let l' = List.map (fun x -> x) l in (* copy the list *)
let rec aux = function
| [] -> assert false
| [_] as lst -> (* find the last cons cell *)
(* and set the last pointer to the beginning of the list *)
Obj.set_field (Obj.repr lst) 1 (Obj.repr l')
| _::t -> aux t
in aux l'; l'
Please be aware that using the Obj module is highly discouraged. On the other hand, there are industrial-strength programs and libraries (Coq, Jane Street's Core, Batteries included) that are known to use this sort of forbidden art.
camlspotter's answer is good enough already. I just want to add several more points here.
First of all, for the problem of write a function that receives a finite list and returns an infinite, circular version of it, it can be done in code / implementation level, just if you really use the function, it will have stackoverflow problem and will never return.
A simple version of what you were trying to do is like this:
let rec circle1 xs = List.rev_append (List.rev xs) (circle1 xs)
val circle: 'a list -> 'a list = <fun>
It can be compiled and theoretically it is correct. On [1;2;3], it is supposed to generate [1;2;3;1;2;3;1;2;3;1;2;3;...].
However, of course, it will fail because its run will be endless and eventually stackoverflow.
So why let rec circle2 = 1::2::3::circle2 will work?
Let's see what will happen if you do it.
First, circle2 is a value and it is a list. After OCaml get this info, it can create a static address for circle2 with memory representation of list.
The memory's real value is 1::2::3::circle2, which actually is Node (1, Node (2, Node (3, circle2))), i.e., A Node with int 1 and address of a Node with int 2 and address of a Node with int 3 and address of circle2. But we already know circle2's address, right? So OCaml just put circle2's address there.
Everything will work.
Also, through this example, we can also know a fact that for a infinite circled list defined like this actually doesn't cost limited memory. It is not generating a real infinite list to consume all memory, instead, when a circle finishes, it just jumps "back" to the head of the list.
Let's then go back to example of circle1. Circle1 is a function, yes, it has an address, but we do not need or want it. What we want is the address of the function application circle1 xs. It is not like circle2, it is a function application which means we need to compute something to get the address. So,
OCaml will do List.rev xs, then try to get address circle1 xs, then repeat, repeat.
Ok, then why we sometimes get Error: This kind of expression is not allowed as right-hand side of 'let rec'?
From http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s%3aletrecvalues
the let rec binding construct, in addition to the definition of
recursive functions, also supports a certain class of recursive
definitions of non-functional values, such as
let rec name1 = 1 :: name2 and name2 = 2 :: name1 in expr which
binds name1 to the cyclic list 1::2::1::2::…, and name2 to the cyclic
list 2::1::2::1::…Informally, the class of accepted definitions
consists of those definitions where the defined names occur only
inside function bodies or as argument to a data constructor.
If you use let rec to define a binding, say let rec name. This name can be only in either a function body or a data constructor.
In previous two examples, circle1 is in a function body (let rec circle1 = fun xs -> ...) and circle2 is in a data constructor.
If you do let rec circle = circle, it will give error as circle is not in the two allowed cases. let rec x = let y = x in y won't do either, because again, x not in constructor or function.
Here is also a clear explanation:
https://realworldocaml.org/v1/en/html/imperative-programming-1.html
Section Limitations of let rec
Here's what I've got so far...
fun positive l1 = positive(l1,[],[])
| positive (l1, p, n) =
if hd(l1) < 0
then positive(tl(l1), p, n # [hd(l1])
else if hd(l1) >= 0
then positive(tl(l1), p # [hd(l1)], n)
else if null (h1(l1))
then p
Yes, this is for my educational purposes. I'm taking an ML class in college and we had to write a program that would return the biggest integer in a list and I want to go above and beyond that to see if I can remove the positives from it as well.
Also, if possible, can anyone point me to a decent ML book or primer? Our class text doesn't explain things well at all.
You fail to mention that your code doesn't type.
Your first function clause just has the variable l1, which is used in the recursive. However here it is used as the first element of the triple, which is given as the argument. This doesn't really go hand in hand with the Hindley–Milner type system that SML uses. This is perhaps better seen by the following informal thoughts:
Lets start by assuming that l1 has the type 'a, and thus the function must take arguments of that type and return something unknown 'a -> .... However on the right hand side you create an argument (l1, [], []) which must have the type 'a * 'b list * 'c list. But since it is passed as an argument to the function, that must also mean that 'a is equal to 'a * 'b list * 'c list, which clearly is not the case.
Clearly this was not your original intent. It seems that your intent was to have a function that takes an list as argument, and then at the same time have a recursive helper function, which takes two extra accumulation arguments, namely a list of positive and negative numbers in the original list.
To do this, you at least need to give your helper function another name, such that its definition won't rebind the definition of the original function.
Then you have some options, as to which scope this helper function should be in. In general if it doesn't make any sense to be calling this helper function other than from the "main" function, then it should not be places in a scope outside the "main" function. This can be done using a let binding like this:
fun positive xs =
let
fun positive' ys p n = ...
in
positive' xs [] []
end
This way the helper function positives' can't be called outside of the positive function.
With this take care of there are some more issues with your original code.
Since you are only returning the list of positive integers, there is no need to keep track of the
negative ones.
You should be using pattern matching to decompose the list elements. This way you eliminate the
use of taking the head and tail of the list, and also the need to verify whether there actually is
a head and tail in the list.
fun foo [] = ... (* input list is empty *)
| foo (x::xs) = ... (* x is now the head, and xs is the tail *)
You should not use the append operator (#), whenever you can avoid it (which you always can).
The problem is that it has a terrible running time when you have a huge list on the left hand
side and a small list on the right hand side (which is often the case for the right hand side, as
it is mostly used to append a single element). Thus it should in general be considered bad
practice to use it.
However there exists a very simple solution to this, which is to always concatenate the element
in front of the list (constructing the list in reverse order), and then just reversing the list
when returning it as the last thing (making it in expected order):
fun foo [] acc = rev acc
| foo (x::xs) acc = foo xs (x::acc)
Given these small notes, we end up with a function that looks something like this
fun positive xs =
let
fun positive' [] p = rev p
| positive' (y::ys) p =
if y < 0 then
positive' ys p
else
positive' ys (y :: p)
in
positive' xs []
end
Have you learned about List.filter? It might be appropriate here - it takes a function (which is a predicate) of type 'a -> bool and a list of type 'a list, and returns a list consisting of only the elements for which the predicate evaluates to true. For example:
List.filter (fn x => Real.>= (x, 0.0)) [1.0, 4.5, ~3.4, 42.0, ~9.0]
Your existing code won't work because you're comparing to integers using the intversion of <. The code hd(l1) < 0 will work over a list of int, not a list of real. Numeric literals are not automatically coerced by Standard ML. One must explicitly write 0.0, and use Real.< (hd(l1), 0.0) for your test.
If you don't want to use filter from the standard library, you could consider how one might implement filter yourself. Here's one way:
fun filter f [] = []
| filter f (h::t) =
if f h
then h :: filter f t
else filter f t
I´m a newbie in SML and I´d like to update my function so that it has two outputs: a list AND 1 or 0. The function was proposed here: SML: Remove the entry from the List. It returns an updated list without a row that contains ´elem´.
fun removeElem elem myList = filter (fn x => x <> elem) myList
The function should return a new list AND 1, if a raw has been deleted. Otherwise, it should return an old list AND 0.
Any hint or example is highly appreciated. Thanks.
Note that all SML functions take a single input and return a single output. Instead, think of returning a tuple containing the new list and a flag indicating whether any elements were removed. One possibility is to use a couple of functions from the standard basis to test whether elem is in myList and build up a tuple consisting of that and the results from the filter shown in the question. The test might look like:
Option.isSome (List.find (fn x => x = elem) myList)
There are more concise ways to write that, but it shows the idea. Note that it returns a bool instead of an int; this is more precise, so I won't convert to the integers requested in the question.
A drawback of the above is that it requires traversing the list twice. To avoid that, consider the type that the function must return: a tuple of a list without elem and a flag showing whether any elems have been removed. We can then write a function that take a new value and a (valid) tuple, and returns a valid tuple. One possibility:
fun update(x, (acc, flag)) = if x = elem then (acc, true) else (x :: acc, flag)
We can then apply update to each element of myList one-by-one. Since we want the order of the list to stay the same, apart from the removed elements, we should work through myList from right to left, accumulating the results into an initially empty list. The function foldr will do this directly:
foldr update ([], false) myList
However, there is a lot of logic hidden in the foldr higher-order function.
To use this as a learning exercise, I'd suggest using this problem to implement the function in a few ways:
as a recursive function
as a tail-recursive function
using the higher order functions foldl and foldr
Understanding the differences between these versions will shed a lot of light on how SML works. For each version, let the types guide you.
As has been stated in some of your previous questions; Returning 0 or 1 as an indicator for what happened is a really bad design, as you don't get any guarantees from the types, whether or not you will get -42 as the result. Since you are working with a strongly typed language, you might as well use this to your advantage:
The most obvious thing to do instead would be to return a boolean, as that is actually what you are emulating with 0 and 1. In this case you could return the pair (true, modified_list) or (false, original_list).
Since you want to associate some data with the result, there is another -- perhaps, for some, less -- obvious thing to do; Return the result as an option, indication a change in the list as SOME modified_list and indication no change as NONE.
In either case you would have to "remember" whether or not you actually removed any elements from the original list, and thus you can't use the filter function. Instead you would have to do this for yourself using somewhat the same code as you originally posted.
One way would be like this
fun removeElem _ [] = (false, [])
| removeElem elem (x::xs) =
let
val (b, xs') = removeElem elem xs
in
if elem = x then
(true, xs')
else
(b, x::xs')
end
Another way would be to use a accumulator parameter to store the resulting list
fun removeElem elem xs =
let
fun removeElem' [] true res = SOME (rev res)
| removeElem' [] false _ = NONE
| removeElem' (x::xs) b res =
if elem = x then
removeElem' xs true res
else
removeElem' xs b (x::res)
in
removeElem' xs false []
end
Since the solution is being built in the reverse order, we reverse the result just before we return it. This makes sure that we don't have to use the costly append operation when adding elements to the result list: res # [x]