Understanding Erlang List Comprehension Generators - erlang

Given this function:
pretty_print(Folders, Depth) ->
{CurrrentFolder, ListSubfolders} = Folders,
SignTemp = lists:duplicate(Depth, "-"),
case Depth of
0 -> Sign = SignTemp;
_ -> Sign = "|" ++ SignTemp
end,
io:format("~s~s~n", [Sign, CurrrentFolder]),
[pretty_print(Subfolder, Depth+1)|| Subfolder <- ListSubfolders].
What happens to a recursive function in Erlang when in a list comprehension the generator is null or empty?
So when the variable is empty, the function won't call itself?
Won't it produce an error on that line? There is nothing to control that an error does not occur in this line?
{CurrrentFolder, ListSubfolders} = Folders,
For example in this piece of code, the behaviour of another variable through Depth is controlled:
case Depth of
0 -> Sign = SignTemp;
_ -> Sign = "|" ++ SignTemp
end,
There is something that I do not quite understand here.
What happens to the function when it reaches the last folder of a directory?

¿What happens to a recursive function in Elrang when in a list comprehesion the generator is null or empty?
When a generator in a list comprehension is empty, then the comprehension is empty. Doesn't matter if it's recursive or not.
So when the variable is empty, the function won't call itself?
Yes.
There is nothing to control that an error does not occur in this line?
No, it simply assumes the caller will give an argument which matches it (and that ListSubfolders is a list each element of which also matches it). It would be more idiomatic to match directly in the head:
pretty_print({CurrrentFolder, ListSubfolders}, Depth) ->
SignTemp = lists:duplicate(Depth, "-"),
... %% the rest is the same

What happens to a recursive function in Elrang when in a list
comprehesion the generator is null or empty?
Easy to test:
-module(a).
-compile(export_all).
go(N) ->
[go(X) || X <- [] ].
In the shell:
3> a:go(0).
[]
What would you expect the return value of the following to be:
[ X+1 || X <- [] ]
No different than if you defined:
f(X) -> X+1.
then executed:
[f(X) || X <- [] ]
The function doesn't get called if there is no argument to call the function with.

Just to add more clarity. Below code is not there for the purpose of control - they are 'just' there because for root folder input, we do not want to put '|' character in the front of the folder name (cosmetic stuff). So even if you change it to whichever: Sign = SignTemp or Sign = "|" ++ SignTemp only, it won't change the logic.
case Depth of
0 -> Sign = SignTemp;
_ -> Sign = "|" ++ SignTemp
end,
In the previous code, Folders will never be [], it will at least have the value of {CurrentFolder, []} (the one that could be an empty list is ListSubfolders).
And since below list comprehension is applied to ListSubfolders, it is safe because if ListSubfolders is [], pretty_print will not be called.
[pretty_print(Subfolder, Depth+1)|| Subfolder <- ListSubfolders].

I draw this to illustrate how the list comprehension works, with all recursive call of your function pretty_print.

Related

Concatenating lists with recursion f#

I have an exercise that asks me to make a recursive function that uses # to create a list of [1;2;3..n]. Unfortunately I cannot get this method to work.
let lstInt: int list = []
let rec oneToN (n:int) : int list =
let addList = [n]
match n with
0 ->
lstInt
|_ ->
lstInt#addList
oneToN (n-1)
I have tried making my list mutable, but that doesn't seem to actually matter nor make much sense as you can still add and remove elements from lists in f# even though it is not mutable.
I have also tried removing space between # but that shouldn't matter either.
Edit: I should clarify, the issue is the lstInt#addList, which gives me the error:
"The result of this expression has type 'int list' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr"
That warning is not the issue, but it points you to the issue: you're creating a new list which is a concatenation of an empty list and [n], but then you're doing nothing with that new list. It's just dropped on the floor.
After that, you proceed to call oneToN (n-1) recursively and return its result. At the end of recursion, the very last call to oneToN will ultimately return an empty list, and that will be the return value of every previous iteration, since every iteration (except the last one) returns whatever the next iteration returns.
What you need to do is call oneToN (n-1), which will give you a list of numbers from 1 to n-1, and then append [n] to that list. And the result of that appending would be your return value: after all, if you take a list of numbers from 1 to n-1 and attach n to the end of it, you'll get a list of numbers from 1 to n.
let rec oneToN (n:int) : int list =
let addList = [n]
match n with
0 ->
lstInt
|_ ->
(oneToN (n-1)) # addList

F# pattern matching with optional list of tuples

I'm trying to use pattern matching for an optional list of tuples but I could not write an exhaustive matching expression despite trying everything I can think of.
I'm struggling to understand why the F# compiler is insisting that my patterns in the following examples are not exhaustive.
module Mapper.PatternMatchingOddity
type A = A of string
type B = B of string
type ProblemType = ProblemType of (A * B) list option
//Incomplete pattern matches on this expression. Some ([_;_]) may indicate a case...
let matchProblem = function
|Some [(x:A,y:B)] -> []
|Some ([_,_]) -> [] //rider says this rule will never be matched
|None -> []
//same as before
let matchProblem1 = function
|Some [_,_] -> []
|Some [] -> []
//|Some _ -> []//this removes the warning but what is the case not covered by the previous two?
|None -> []
let matchProblem2 (input:ProblemType) =
match input with //same as before
|ProblemType (Some [(x:A,y:B)]) -> []
|ProblemType None -> []
How do I write the exhaustive matching and what am I missing above? Can you give an example for an input that would be accepted as a valid parameter to these functions and slip through the patterns?
Great question! I think many people that start out with F# grapple with how lists, options and tuples interact. Let me start by saying: the compiler is correct. The short answer is: you are only matching over singleton lists. Let me try to explain that a little deeper.
Your type is ('a * 'b) list option, essentially. In your case, 'a and 'b are themselves a single-case discriminated using of a string. Let's simplify this a bit and see what happens if we look at each part of your type in isolation (you may already know this, but it may help to put it in context):
First of all, your type is option. This has two values, None or Some 'a. To match over an option you can just do something like
match o with
| Some value -> value
| None -> failwith "nothing"`
Next, your type is a list. The items in a list are divided by semicolons ;. An empty list is [], a singleton list (one with a single item) is [x] and multiple items [x;y...]. To add something to the start of a list use ::. Lists are a special type of discriminated union and the syntax to match over them mimics the syntax of lists construction:
match myList with
| [] -> "empty"
| [x] -> printfn "one item: %A" x
| [x; y] -> printfn "two items: %A, %A" x y
| x::rest -> printfn "more items, first one: %A" x
Third, your list type is itself a tuple type. To deconstruct or match over a tuple type, you can use the comma ,, as with match (x, y) with 1, 2 -> "it's 1 and 2!" ....
Combine all this, we must match over an option (outer) then list (middle) then tuple. Something like Some [] for an empty list and None for the absence of a list and Some [a, b] for a singleton list and Some (a,b)::rest for a list with one or more items.
Now that we have the theory out of the way, let's see if we can tackle your code. First let's have a look at the warning messages:
Incomplete pattern matches on this expression. Some ([_;_]) may indicate a case...
This is correct, the item in your code is separated by , denoting the tuple, and the message says Some [something; something] (underscore means "anything"), which is a list of two items. But it wouldn't help you much to add it, because the list can still be longer than 2.
rider says this rule will never be matched
Rider is correct (which calls the FSC compiler services underneath). The rule above that line is Some [(x:A,y:B)] (the :A and :B are not needed here), which matches any Some singleton array with a tuple. Some [_,_] does the same, except that it doesn't catch the values in a variable.
this removes the warning but what is the case not covered by the previous two?
It removes the warning because Some _ means Some with anything, as _ means just that: it is a placeholder for anything. In this case, it matches the empty list, the 2-item list, the 3-item list the n-item list (the only one your match is the 1-item list in that example).
Can you give an example for an input that would be accepted as a valid parameter
Yes. Valid input that you were not matching is Some [] (empty list), Some [A "a", B "x"; A "2", B "2"] (list of two items) etc.
Let's take your first example. You had this:
let matchProblem = function
|Some [(x:A,y:B)] -> [] // matching a singleton list
|Some ([_,_]) -> [] // matches a singleton list (will never match, see before)
|None -> [] // matches None
Here's what you (probably) need:
let notAProblemAnymore = function
// first match all the 'Some' matches:
| Some [] -> "empty" // an empty list
| Some [x,y] -> "singleton" // a list with one item that is a tuple
| Some [_,a;_,b] -> "2-item list" // a list with two tuples, ignoring the first half of each tuple
| Some ((x,y)::rest) -> "multi-item list"
// a list with at least one item, and 'rest' as the
// remaining list, which can be empty (but won't,
// here it has at least three items because of the previous matches)
| None -> "Not a list at all" // matching 'None' for absence of a list
To sum it up: you were matching over a list that had only one item and the compiler complained that you missed lists of other lengths (empty lists and lists that have more than one item).
Usually it is not necessary to use option with a list, because the empty list already means the absence of data. So whenever you find yourself writing the type option list consider whether just list would suffice. It will make the matching easier.
You are struggling because your example is too “example”.
Let’s convert your example to a more meaningful one: check the input, so that
If it is none then print “nothing”, otherwise:
If it has zero element then print “empty”
If it has only one element then print “ony one element: ...”
If it has two elements then print “we have two elements: ...”
If it has three elements then print “there are three elements: ...”
If it has more than three elements then print “oh man, the first element is ..., the second element is ..., the third element is ..., and N elements more”
Now you can see that your code only covers the first 3 cases. So the F# compiler was correct.
To rewrite the code:
let matchProblem (ProblemType input) =
match input with
| None -> printfn "nothing"
| Some [] -> ...
| Some [(x, y)] -> ...
| Some [(x1, y1); (x2, y2)] -> ...
| Some [(x1, y1); (x2, y2); (x3, y3)] -> ...
| Some (x1, y1) :: (x2, y2) :: (x3, y3) :: rest -> // access rest.Length to print the number of more elements
Notice that I’m using pattern matching on the parameter ProblemType input so that I can extract the input in a convenient way. This makes the later patterns simpler.
Personally, when I learned F#, I didn’t understand many features/syntax until I used them in production code.

Understanding '_' variable in Erlang

Erlang newbie here. I am from a Java background and am finding Erlan rather interesting. Am following the excellent book "Learn You some Erlang".
Here's an example for recursion as given in the book for reversing the order of a List:
tail_reverse(L) -> tail_reverse(L,[]).
tail_reverse([],Acc) -> Acc;
tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).
This works as expected. However, if I changed the code to:
tail_reverse(L) -> tail_reverse(L,[]).
tail_reverse([],_) -> [];
tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).
this now always returns [] irrespective of the contents of the List passed. So it seems that the line tail_reverse([],_) -> []; is the one getting called. However, my understanding is that it should be called only if the first parameter is empty and _ is just a placeholder.
What am I missing here?
This line:
tail_reverse([], Acc) -> Acc
is supposed to return the accumulating argument Acc when the processed list becomes empty. You replaced it with:
tail_reverse([], _) -> []
which is executed in the same case (the bottom of the recursion), but ignores the previously done work and returns the empty list.
As for the _ variable, it has not much to do with your problem, but it's explained in this answer.
#bereal's answer is correct. However, I am going to provide my own answer to general question of "How does the _ variable work in Erlang. I recently wrote a blog post on the _ variable:
The anonymous variable is denoted by a single underscore (_). The anonymous variable is used when a variable is required but the value needs to be ignored. The anonymous variable never actually has the value bound to it. Since the value is never bound it can be used multiple times in a pattern and each time it is allowed to match a different value. Example:
1> {_, _} = {foo, bar}.
{foo, bar}
2> _.
* 1: variable '_' is unbound
4> {_, Second} = {foo, bar}.
{foo, bar}
5> _.
* 1: variable '_' is unbound
6> Second.
bar
More is available here:
http://stratus3d.com/blog/2014/11/05/everything-you-need-to-know-about-erlangs-magic-variable/

How do I choose the first tuple within a list and save the rest of the tuples in Erlang?

I want be able to input the following:
fun([{X,Y}, {A,B}, {M,N}]).
and only use the first tuple and save the others for later use. I tried defining it like this:
fun([{X|Y}, V]) ->
V.
But I just get a syntax error before the "|". "V" was just to try and output to see what was happening.
Is there any resources I can be pointed towards for some support with this? Or am I doing something really wrong?
func([{X,Y}| V]) -> %% fun is a keyword, you cannot use it as a function name
%% do some stuff with X, Y
V.
generally, if you want to apply the same function to all element of a list, it is good to use the lists module: (lists:foreach/2, lists:map/2, lists:foldl/2 ...) or a list comprehension
Res = [Fun(T) || T <- L]
wher Fun is the function to apply to each tuple T from the list L
you should write like this:
fun([{X, Y} | V]).
[{X, Y} | V] = [{X,Y}, {A,B}, {M,N}], then V = [{A,B}, {M,N}]

Pattern matching on bson tuples

The bson-erlang module turns BSON-encoded JSON such as this:
{ "salutation" : "hello",
"subject" : "world" }
Into an Erlang tuple like this:
{ salutation, <<"hello">>, subject, <<"world">> }
Now, the server I'm attempting to talk to can put those fields in any order, and there might be extra fields in there that I don't care about, so -- equally validly -- I might see this instead:
{ subject, <<"world">>, salutation, <<"hello">>, reason, <<"nice day">> }
Is there any way that I can specify a function pattern that extracts a particular piece of the tuple, based on the one appearing immediately before it?
If I try the following, it fails with "no function clause matching..." because the arity of the tuple is wrong, and because the fields that I care about aren't in the correct place:
handle({ salutation, Salutation, _, _ }) -> ok.
Is this possible? Is there a better way to do this?
T = { subject, <<"world">>, salutation, <<"hello">>, reason, <<"nice day">> },
L = size(T),
L1 = [{element(I,T),element(I+1,T)} || I <- lists:seq(1,L,2)].
[{subject,<<"world">>},
{salutation,<<"hello">>},
{reason,<<"nice day">>}]
proplists:get_value(salutation,L1).
<<"hello">>
and if you want all in 1:
F = fun(Key,Tup) -> proplists:get_value(Key,[{element(I,Tup),element(I+1,Tup)} || I <- lists:seq(1,size(Tup),2)]) end.
F(reason,T).
<<"nice day">>
F(foo,T).
undefined
There is no pattern that successfully matches values from a variable-length structure after a prefix of an unknown length. This is true for tuples, lists and binaries. Indeed, such a pattern would require to recurse through the structure.
A common approach for a list is to recurse by splitting head and tail, something typical of functional languages.
f_list([salutation, Salutation | _]) -> {value, Salutation};
f_list([_Key, _Value | Tail]) -> f_list(Tail);
f_list([]) -> false.
Please note that this function may fail if the list contains an odd number of elements.
The same approach is possible with tuples, but you need guards instead of matching patterns as there is no pattern to extract the equivalent of the tail of the tuple. Indeed, tuples are not linked lists but structures with a O(1) access to their elements (and their size).
f_tuple(Tuple) -> f_tuple0(Tuple, 1).
f_tuple0(Tuple, N) when element(N, Tuple) =:= salutation ->
{value, element(N + 1, Tuple)};
f_tuple0(Tuple, N) when tuple_size(Tuple) > N -> f_tuple0(Tuple, N + 2);
f_tuple0(_Tuple, _N) -> false.
Likewise, this function may fail if the tuple contains an odd number of elements.
Based on elements in the question, the advantage of guards over bson:at/2 is unclear, though.

Resources