I've been looking at some Erlang recursion examples asked earlier here on stackoverflow.
Specifically with this question Erlang basic recursion with guards
But I can't quite understand how the code works. So I have created a module to see the results it returns with a simple list with 3 elements.
-module(recursion).
-export([start/0]).
start() ->
List = [1,2,3],
Final = delete(1,List),
Final.
delete(_, []) ->
io:format("return []~n~n~n"),
[];
delete(Del, [Del|Xs]) ->
io:format("~p =:= ~p~n",[Del,Del]),
io:format("delete(~p, ~p)~n~n~n~n",[Del,Xs]),
delete(Del, Xs);
delete(Del, [X|Xs]) ->
io:format("~p =/= ~p~n",[Del,X]),
io:format(" [~p|delete(~p, ~p)]~n~n~n~n",[X,Del,Xs]),
[X|delete(Del, Xs)].
And this is the result of the log
1> recursion:start().
1 =:= 1
delete(1, [2,3])
1 =/= 2
[2|delete(1, [3])]
1 =/= 3
[3|delete(1, [])]
return [] The result of the 'Final' variable of the main function, shouldn't it be []?
bacause [3|delete(3, [])] in the last call matches with delete(_, []) -> []
or is it this way? [2,[3,[]]] -> [2,3]
[2,3]
2>
My question is:
Every time the program calls delete(Del, [X|Xs]) ->, is the function returning the value to the previous call?
Is it being stored somewhere?
or is it just something like that? [2,[3,[]]] -> [2,3]
edit:
I think I have found the solution in this link, about how the final result is built
https://learnyousomeerlang.com/starting-out-for-real#lists
where
13> List = [2,3,4].
[2,3,4]
14> NewList = [1|List].
[1,2,3,4]
So [2|[3|[]]] -> [2,3]
is that so?
Yes.
This is how the function works:
If the head of the list matches the first argument, 1 in this case, then the head of the list isn't saved anywhere, i.e. it's skipped, and the function is called again with the tail of the list:
delete(Del, [Del|Xs]) ->
delete(Del, Xs);
If the head of the list does NOT match the first argument, then the head of the list is saved by adding it to a result list:
[X|delete(Del, Xs)].
When the list is empty, the function returns [], which is very important when cons'ing elements together:
[3 | f(X) ]
if f(X) does not return a list at some point, then the list won't be a proper list. A proper list, such as:
[1, 2, 3]
is equivalent to:
[1 | [2 | [3 | [] ]]]
as you can see here:
2> [1 | [2 | [3 | [] ]]].
[1,2,3]
When you write:
[X|delete(Del, Xs)]
that's a little be tricky, and you need some experience to know how that works. You can understand things better, by writing out by hand what is happening:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | delete(1, [3]) ] %% Can't know the result here without determining the return value of delete(1, [3])
|
V
[3 | delete(1, []) ] %% Can't know the result here without determining the return value of delete(1, [])
|
V
[]
Once, you've got the return value [], because there are no more function calls in the result, now you can move upwards substituting:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | delete(1, [3]) ]
|
V
[3 | [] ]
And substituting again:
delete(1, [1,2,3])
|
V
delete(1, [2, 3])
|
V
[2 | [3 | [] ] ]
which is equivalent to:
[2, 3]
Here is a conceptually simpler version of delete():
start() ->
List = [1,2,3],
Final = delete(1,List),
Final.
delete(Term, List) ->
delete(Term, List, _Acc=[]).
delete(_, [], Acc) ->
Acc;
delete(Term, [Term|Xs], Acc) ->
delete(Term, Xs, Acc);
delete(Term, [X|Xs], Acc) ->
delete(Term, Xs, [X|Acc]).
However, the result is:
[3, 2]
So, when you use an accumulator variable, you need to reverse the final result:
delete(_, [], Acc) ->
lists:reverse(Acc);
Related
I am working on creating a function called repeat that takes two int lists lst1 and lst2. Assume that lst2 only has nonnegative integers, repeats the integers in the first list lst1 according to the numbers indicated by the second list lst2. If both lists are empty, return an empty list. You may need a local function.
Example:
repeat ([1,2,3], [4,0,3]) -> [1,1,1,1,3,3,3]
I am having a little trouble with getting started with this function. What should I put after the xs?
fun repeat(lst1, lst2) =
case lst1 of
[] => []
| x::xs' => [] (* what should I put here *)
Like any recursion problem, what's your base case? I'd say in this case it's both lists are empty and it gives you an empty list.
fun repeat([], []) = []
What if one is empty but the other isn't? That's a failure. Let's define an exception we can throw if this happens.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
Now the real question is what we do the rest of the time. Fortunately, SML makes it easy to pattern match both lists and extract their first elements.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
| repeat(x::xs, y::ys) = ...
At this point, we need a recursive function to repeat an element of the list a certain number of times. As with the overall function, here we see the two hallmarks of recursion: at least one base "exit" condition, and an update step where we converge toward the base condition by updating n to n - 1.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
| repeat(x::xs, y::ys) =
let
fun repeat'(_, 0) = []
| repeat'(x, n) = x :: repeat'(x, n - 1)
in
...
end
Now, we just need to put it all together, by feeding x and y to repeat' and then concatenating that with the result of calling repeat again with xs and ys. By doing this, we converge down toward the base case of repeat([], []) or we may converge toward a mismatched scenario where a MismatchedArguments exception is raised.
exception MismatchedArguments;
fun repeat([], []) = []
| repeat([], _) = raise MismatchedArguments
| repeat(_, []) = raise MismatchedArguments
| repeat(x::xs, y::ys) =
let
fun repeat'(_, 0) = []
| repeat'(x, n) = x :: repeat'(x, n - 1)
in
repeat'(x, y) # repeat(xs, ys)
end
Now repeat([1, 2, 3], [4, 0, 3]) will yield [1, 1, 1, 1, 3, 3, 3].
I am a new at F# and i try to do this task:
Make a function compare : string list -> string list -> int that takes two string lists and returns: -1, 0 or 1
Please help. I spend a lot of time, and i can not understand how to implement this task.
Given the task I assume what your professor wants to teach you with this exercise. I'll try to give you a starting point without
Confusing you
Presenting a 'done-deal' solution
I assume the goal of this task is to work with recursive functions and pattern matching to element-wise compare their elements. It could looks somewhat like this here
open System
let aList = [ "Apple"; "Banana"; "Coconut" ]
let bList = [ "Apple"; "Banana"; "Coconut" ]
let cList = [ "Apple"; "Zebra" ]
let rec doSomething f (a : string list) (b : string list) =
match (a, b) with
| ([], []) ->
printfn "Both are empty"
| (x::xs, []) ->
printfn "A has elements (we can unpack the first element as x and the rest as xs) and B is empty"
| ([], x::xs) ->
printfn "A is empty and B has elements (we can unpack the first element as x and the rest as xs)"
| (x::xs, y::ys) ->
f x y
printfn "Both A and B have elements. We can unpack them as the first elements x and y and their respective tails xs and ys"
doSomething f xs ys
let isItTheSame (a : string) (b : string) =
if String.Equals(a, b) then
printfn "%s is equals to %s" a b
else
printfn "%s is not equals to %s" a b
doSomething isItTheSame aList bList
doSomething isItTheSame aList cList
The example has three different lists, two of them being equal and one of them being different. The doSomething function takes a function (string -> string -> unit) and two lists of strings.
Within the function you see a pattern match as well as a recursive call of doSomething in the last match block. The signatures aren't exactly what you need and you might want to think about how to change the parametrization for cases where you don't want to stop the recursion (the last match block - if the strings are equal you want to keep on comparing, right?).
Just take the code and try it out in FSI. I'm confident, that you'll find the solution 🙂
In F# many collections are comparable if their element type is:
let s1 = [ "a"; "b" ]
let s2 = [ "foo"; "bar" ]
compare s1 s2 // -5
let f1 = [ (fun () -> 1); fun () -> 2 ]
let f2 = [ (fun () -> 3); fun () -> 42 ]
// compare f1 f2 (* error FS0001: The type '(unit -> int)' does not support the 'comparison' constraint. *)
so
let slcomp (s1 : string list) s2 = compare s1 s2 |> sign
Posting for reference as the original question is answered already.
I'm reading https://ocaml.org/learn/tutorials/99problems.html and it has 2 examples:
# let rec last_two = function
| [] | [_] -> None
| [x;y] -> Some (x,y)
| _::t -> last_two t;;
I understand the first one: _::t means pattern match anything and call it t
But at
# let rec at k = function
| [] -> None
| h :: t -> if k = 1 then Some h else at (k-1) t;;
I don't understand what h means. For me it should be _:: t -> ... to match anything and call it t
The pattern _ :: t doesn't mean what you say. It matches any non-empty list and calls the tail of the list t.
The pattern h :: t matches any non-empty list, calls the head of the list h (one element, the first one), and the tail of the list t (zero or more elements after the first one).
The operator :: is the list constructor (often called "cons"), which is why these patterns match lists.
Here are examples of :: as list constructor:
# true :: [];;
- : bool list = [true]
# 1 :: [2; 3];;
- : int list = [1; 2; 3]
As is usual in OCaml, the pattern for a list uses the same syntax as the constructor.
# match [1;2;3] with [] -> None | h :: t -> Some (h, t);;
- : (int * int list) option = Some (1, [2; 3])
The h::t pattern matches the head and tail of the list to the variables h and t.
So if I pattern match like this:
match [1; 2; 3] with
| h::t -> (* Some code... *)
h will have a value of 1, and t will have the value of [2; 3].
:: is a constructor. Pattern matching in this fashion pattern matches against constructors. They create a new datatype out of two values. :: is a constructor, and its type, list, is recursive. Here's a sample definition of the list type:
type 'a list =
| []
| (::) 'a * ('a list)
;;
So the list type is recursive because its constructor, ::, calls itself.
Honestly, I could write half a book on lists. They're the bread and butter of functional programming languages.
If you're wondering why you can't pattern match on operators, this is why. You can't pattern match on operators, only constructors.
Yes, indeed when you type in a function let's take for example this one:
let is_empty (l: int list) : int =
begin match l with
| [] -> 1
| h::t -> 0
end;;
Therefore, in this function that tests if a list is empty or not, if [], an empty list it returns one or in boolean true but if h::t, meaning that there is one or more value, the function returns 0, meaning it's false.
I know there are other ways to avoid using Accumulators and the built in ++ will append one list to another list. However, if I build my own tail recursive append function with an accumulator, is there any way of getting around using lists:reverse() on one of the lists like the snippet below? Thanks
joinWithAccumulator2(X,Y) ->
joinWithAccumulator2(lists:reverse(X), [], Y).
joinWithAccumulator2( [], [], A ) ->
A;
joinWithAccumulator2( [X | Xs], [], A ) ->
joinWithAccumulator2( Xs, [], [ X | A] ).
The fastest way to build a list is to prepend elements using [H|T]. So the way you did it is efficient. If your purpose is to avoid to use the lib library, and in order to use the accumulator (see #juan.facorro comment) you can first reverse the first list in the accumulator, then prepend it to the second list:
joinWithAccumulator2(LX, LY) ->
joinWithAccumulator2(LX, LY, []).
% first step reverse LX in LA
joinWithAccumulator2( [X | Xs], LY, LA ) ->
joinWithAccumulator2( Xs, LY, [X | LA] );
% second step, when LX is empty, prepend LA to LY (list accumulator2)
joinWithAccumulator2( [], LA2, [A | As] ) ->
joinWithAccumulator2( [], [A | LA2], As );
% operation done
joinWithAccumulator2( [], A, [] ) ->
A.
I wanted to write a map for an infinite list.
This is, what I have so far:
-module(map).
-export([ints/0,take/2,map/2, double_int/1]).
ints() -> ints_from(0).
take(0, _) -> [];
take(N, [H|LazyT]) -> [H | take(N-1, LazyT())].
double_int(N) -> 2 * N.
map(_, []) -> [];
map(F, [H | T]) -> [F(H) | map(F, T())].
ints_from(N) -> [N | fun () -> ints_from(N+1) end].
The problem is, that with the call
> L = map:ints().
[0|#Fun<map.0.104601022>]
> R = map:map(fun map:double_int/1, L).
I get a never ending process. I guess, the map is proceeding through the whole infinite list and therefore never ending.
What am I doing wrong?
Since you represent lazy lists as lists whose tail is a function, your definition of map needs to return such a value as well:
map(_, []) -> [];
map(F, [H | T]) -> [F(H) | fun() -> map(F, T()) end].