I am trying to turn a tuple of the form:
{{A,B,{C,A,{neg,A}}},{A,B,{neg,A}}}
Into
{{A,B,C,A,{neg,A}},{A,B,{neg,A}}
I'm quite new to Erlang so I would appreciate any hints. It makes no difference if the final structure is a list or a tuple, as long as any letter preceded by neg stays as a tuple/list.
A simple solution:
convert({{A,B,{C,D,E}},F}) -> {{A,B,C,D,E},F}.
If why this works is puzzling, consider:
1> YourTuple = {{a, b, {c, a, {neg, a}}}, {a, b, {neg, a}}}.
{{a,b,{c,a,{neg,a}}},{a,b,{neg,a}}}
2> Convert = fun({{A,B,{C,D,E}},F}) -> {{A,B,C,D,E},F} end.
#Fun<erl_eval.6.54118792>
3> Convert(YourTuple).
{{a,b,c,a,{neg,a}},{a,b,{neg,a}}}
The reason this happens is because we are matching over entire values based on the shape of the data. That's the whole point of matching, and also why its super useful in so many cases (and also why we want to use tuples in more specific circumstances in a language with matching VS a language where "everything is an iterable"). We can substitute the details with anything and they will be matched and returned accordingly:
4> MyTuple = {{"foo", bar, {<<"baz">>, balls, {ugh, "HURR!"}}}, {"Fee", "fi", "fo", "fum"}}.
{{"foo",bar,{<<"baz">>,balls,{ugh,"HURR!"}}},
{"Fee","fi","fo","fum"}}
5> Convert(MyTuple).
{{"foo",bar,<<"baz">>,balls,{ugh,"HURR!"}},
{"Fee","fi","fo","fum"}}
Why did this work when the last element of the top-level pair was so different in shape than the first one? Because everything about that second element was bound to the symbol F in the function represented by Convert (note that in the shell I named an anonymous function for convenience, this would be exactly the same as using convert/1 that I wrote at the top of this answer). We don't care what that second element was -- in fact we don't want to have to care about the details of that. The freedom to selectively not care about the shape of a given element of data is one of the key abstractions we use in Erlang.
"But those were just atoms 'a', 'b', 'c' etc. I have different things in there!"
Just to make it look superficially like your example above (and reinforce what I was saying about not caring about exactly what we bound to a given variable):
6> A = 1.
1
7> B = 2.
2
8> C = 3.
3
9> AnotherTuple = {{A, B, {C, A, {neg, A}}}, {A, B, {neg, A}}}.
{{1,2,{3,1,{neg,1}}},{1,2,{neg,1}}}
10> Convert(AnotherTuple).
{{1,2,3,1,{neg,1}},{1,2,{neg,1}}}
Needing to do this is not usually optimal, though. Generally speaking the other parts of the program that are producing that data in the first place should be returning useful data types for you. If not you can certainly hide them behind a conversion function such as the one above (especially when you're dealing with APIs that are out of your control), but generally speaking the need for this is a code smell.
And moving on
The more general case of "needing to flatten a tuple" is a bit different.
Tuples are tuples because each location within it has a meaning. So you don't usually hear of people needing to "flatten a tuple" because that fundamentally changes the meaning of the data you are dealing with. If you have this problem, you should not be using tuples to begin with.
That said, we can convert a tuple to a list, and we can check the shape of a data element. With these two operations in hand we could write a procedure that moves through a tuplish structure, building a list out of whatever it finds inside as it goes. A naive implementation might look like this:
-module(tuplish).
-export([flatten/1]).
-spec flatten(list() | tuple()) -> list().
flatten(Thing) ->
lists:flatten(flatten(Thing, [])).
flatten(Thing, A) when is_tuple(Thing) ->
flatten(tuple_to_list(Thing), A);
flatten([], A) ->
lists:reverse(A);
flatten([H | T], A) when is_tuple(H) ->
flatten(T, [flatten(H) | A]);
flatten([H | T], A) when is_list(H) ->
flatten(T, [flatten(H) | A]);
flatten([H | T], A) ->
flatten(T, [H | A]).
Keep in mind that after several years of writing Erlang code I have never needed to actually do this. Remember: tuples mean something different than lists.
All that said, the problem you are facing is almost certainly handled better by using records.
Related
In OOP land, take for example Roslyn and it's syntax rewriters, using visitor pattern.
This is very nice, as there is already a base rewriter class, that defines all visit methods with do nothing, and I just have to override the methods that I care about.
What would be a comparable solution with the DU kind of ASTs?
Eg if I would like to write a function that visits every node of an AST parsed with the following snippet (not made by me))
I can write transformer functions like so
// strip all class type modifiers because of reasons
let typeTransformer (input:CSharpType) : CSharpType =
match input with
| Class (access, modifier, name, implements, members) ->
Class (access, None, name, implements, members)
| _ -> input
let rec nameSpaceTransformer typeTransformer (input:NamespaceScope) : NamespaceScope =
match input with
| Namespace (imports, names, nestedNamespaces) ->
Namespace (imports, names, List.map (nameSpaceTransformer typeTransformer) nestedNamespaces)
| Types (names, types) ->
Types (names, List.map typeTransformer types)
This is already pretty cumbersome, but it gets worse and worse, the deeper one gets into the tree.
Does this representation just not lend itself to these kinds of transformations?
Edit: what I am actually looking for, is a way where I can define just the specific transform functions that will then be automatically applied to the correct nodes, while everything else remains unchanged.
Here is my best try so far on a simplified example (Fable REPL)
Note the last 2 lets after the comment, in later usage, one should only need to write those 2 and then call transform replaceAllAsWithBsTransformer someAstRoot with an actual AST instance.
Of course this solution does not work correctly, because it would require recursive records. (eg the transformMiddleNode function should really ask for a the transformer record itself and ask for it's transformLeaf member).
This is the part where I have trouble with, and which I would say is nicely solved by OOP visitor pattern, but I can't figure out how to mirror it successfully here.
Edit 2:
At the end of the day, I went with just implementing an actual visitor class in the form of
type Transformer() =
abstract member TransformLeaf : Leaf -> Leaf
default this.TransformLeaf leaf = id leaf
abstract member TransformMiddleNode : MiddleNode -> MiddleNode
default this.TransformMiddleNode node =
match node with
| MoreNodes nodeList ->
List.map this.TransformMiddleNode nodeList
|> MoreNodes
| Leaf leaf -> this.TransformLeaf leaf |> Leaf
abstract member TransformUpperNode : UpperNode -> UpperNode
default this.TransformUpperNode node =
match node with
| MoreUpperNodes nodeList ->
List.map TransformUpperNode nodeList |> MoreUpperNodes
| MiddleNodes nodeList ->
List.map TransformMiddleNode nodeList |> MiddleNodes
...
and then I can define specific transformations like:
type LeafTransformer()
inherit Transformer()
override this.TransformLeaf leaf = someLeafTransformation leaf
where someLeafTransformation: Leaf -> Leaf
This is not any worse than the OOP solution (is essentially the same, except the "bottom level" visitor interfaces are replaced by pattern matching.
Certainly the code you posted is doing it the "functional way". It's not clear to me exactly how this is "cumbersome" or "gets worse the deeper one gets into the tree". I think the key concept here is just to write your functions as concisely as possible (but not so concise they become unreadable!) and then figuring out the right mix of helper functions and higher level functions that rely on those, plus good comments where needed.
Your first function could just be this:
let transformModifier input =
match input with
| Class (a, modifier, c, d, e) -> (a, None, b, c, d)
| _ -> input
This is less verbose, but still readable. In fact, it's probably more readable as it's obvious now that the only thing this does is change the class modifier.
Perhaps you will want to create other functions that modify classes, and compose these using >>, then call them from a larger function that walks the whole tree.
The ultimate readability of the code is going to be mostly up to you (IMO).
There are good discussions of AST transformations in the books Expert F# and F# Deep Dives.
what I am actually looking for, is a way where I can define just the specific transform functions that will then be automatically applied to the correct nodes, while everything else remains unchanged.
I wrote an AST transformation library called FSharp.Text.Experimental.Transform that does exactly this. Coincidentally I've already written a C# grammar definition so I was able to use to try out your "strip class modifiers" problem.
Your solution, implemented using this library, starts by feeding the C# grammar definition into the GrammarProvider type provider. The type provider will provide methods for parsing the input text, and provides a type for each non-terminal in the grammar.
open FSharp.Text.Experimental.Transform
type CSharp = GrammarProvider<"csharp.grm">
Next, you define your transformation function that just operates on the nodes you care about. Since you care about transforming the modifiers for a class, you'll target the
ClassModifier* part of the ClassDefinition grammar production
// This function replaces any list of class modifiers with the empty list
let stripClassModifiers (_: CSharp.ClassModifier list) = []
Finally, you parse the input text, apply your transformation function, then unparse to a string:
CSharp.ParseFile("path/to/program.cs").ApplyOnePass(stripClassModifiers).ToString()
The ApplyOnePass() method will perform a single pass over the AST, applying your stripClassModifiers transformation wherever it finds a list of class modifiers and leaving all the other nodes untouched.
The library contains more powerful methods for more complex transformations, but I hope the example above suffices to illustrate the idea. See the library documentation for tutorials, examples, API reference, and more details on what it can do.
This is an example of my current code:
DataSet = [1,2,3,4,5,6,7,8,9].
Sequence = [3,4,5,6].
ReducedDataSet = lists:foldl( fun(SeqNumber, Output) ->
Row = lists:nth(SeqNumber, DataSet),
[Row|Output]
end,
[],
Sequence
).
ReducedDataSet ends up as [6,5,4,3] and if I change it to lists:foldr, ReducedDataSet would be [3,4,5,6].
I didn't expect this as when absorbed left to right, the 3rd value is 3 and should proceed to 6, but when absorbed right to left, the 3rd value would be 7, and proceed to 4.
Does this mean there's a hidden row number on my list, and foldl and foldr only differ in the sort order of the final list?
I think this is a more general fold question.
In general, fold performs the following: (new_element, acc) -> new_acc
If the operation new_element ° acc is commutative (e.g. the sum), foldl and foldr are the same.
If the operation is "append" there is a difference between appending the element to the left or to the right.
[3] ° 4 -> [3, 4] VS 4 ° [3] -> [4, 3]
I never remember which is foldl and foldr but I think left/right refers to the position of the accumulator ([3] ° 4 is foldl with this definition)
TL;DR
No, there is no hidden index or "row number" in an Erlang list.
Discussion
It may be helpful to explore the nature of list operations a bit more in the context of functional lists of the "lists are a bunch of conses" variety.
I wrote an explanation of folds a while back that might be useful to you: Explanation of lists:fold function
Keep in mind that functional lists only have pointers that go one-way. That is, they are singly linked lists. There is no concept of a "rownum" or "index" as it would be in a C style array. Each call to lists:nth/2 is actually traversing the list to the nth element before returning that element.
We could write lists:nth/2 like this if we want a version that crashes on bad input (and, looking it up, it turns out that it is written almost exactly like this):
nth(1, [Element | _]) ->
Element;
nth(N, [_ | Rest]) when N > 1 ->
lists:nth(N - 1, Rest).
(As a side note, consider not inlining funs that require you to write multi-line definitions as function arguments...)
I have a discriminated union with 10-15 cases, all having data in the form of int<'a>:
type MyUnionType =
| Case1 of int<someUnit>
| Case2 of int<someUnit>
|
...
| CaseN of int<someOtherUnit>
I am new to functional programming and am struggling to write a function with the following signature:
mySum:MyUnionType option list -> MyUnionType option
The function should sum all the ints iff all the Some elements belong to the same DU case. For example:
mySum [Some (Case1 2<a>), Some (Case1 3<a>), None] = Some Case1 5<a>
mySum [Some (Case1 2<a>), Some (Case2 3<a>), None] = None
mySum [None] = None
I know about Option.map and List.choose and the likes that can help here, but I'm struggling with determining whether all elements belong to the same case.
Is there an elegant and FP-idiomatic way to write this function? (If it simplifies matters, you can assume the list is never empty.)
(Though I don't have a clear grasp on monoids/monads/morphisms yet, don't be afraid to use the words if relevant, though please stop a bit short of zygohistomorphic prepromorphisms).
First, the code I'm about to present you will be greatly simplified if you remove all the None cases from the list before summing it. So for the rest of my answer, I'm going to assume that you've run your list through a List.choose id step first to get rid of all the None values.
The simplest way to think about this is probably to break it down into a series of single steps. You start by taking the first item of the list to initialize your "sum so far" value. (If there was no first item after running the list through List.choose id, then the list was either empty or contained only Nones, so the sum in that case will be None). Now, if that was the only item of the list, then you've already found the sum of the entire list. Otherwise, you look at the first item of the rest of the list, and ask the following question:
Is that item the same DU case as the sum so far?
If the answer is yes, then you add its value to the sum so far, and keep going through the loop. If the answer is no, then you make the "sum so far" value a None value instead of Some (case). So really, the "is it the same as the sum so far" question is actually two questions:
Is the "sum so far" a real value? (I.e., not None)?
Is the item I'm looking at the same DU case as the sum so far?
If the answer to both of these questions is "yes", then you add up the two values to get a new "sum so far" value. If it's "no", then you just set the "sum so far" to None, and your eventual result will be None as well.
Translating that approach into code looks like this:
let addToSum sumSoFar nextItem =
match sumSoFar with
| None -> None // Short-circuit if we previously found a mismatch
| Some x ->
match x, nextItem with
| Case1 a, Case1 b -> Some (Case1 (a + b))
| Case2 a, Case2 b -> Some (Case2 (a + b))
// ...
| CaseN a, CaseN b -> Some (CaseN (a + b))
| _ -> None // Mismatch
Now you need a function to apply a "combining" operation like that to the whole list. (A "combining" operation is any operation that takes two items of the same type and produces a single item of that same type; addition is one such operation, but so is multiplication, and a bunch of other things). There are two basic "apply this combining operation to the whole list" functions in F#, reduce and fold. The difference is that reduce takes the first item of the list as the initial "sum so far" value, and cannot work on an empty list. Whereas fold requires you to supply the initial value of its "sum so far" accumulator, but it can work on an empty list (for an empty list, the result of fold will simply be the initial "sum so far" value that you provided). In your case, since you don't initially know the type that your "sum so far" value should hold, you have to use reduce. So I'd suggest something like this:
let sumMyList values =
values |> List.choose id |> List.reduce addToSum
Except that List.reduce can't handle an empty list, and if the list you have is entirely None cases, that would blow up. (Can you see why?) So I'll add one more step to it, to handle empty lists:
let reduceSafely filteredValues =
match filteredValues with
| [] -> None
| _ -> filteredValues |> List.reduce addToSum
let sumMyList values =
values |> List.choose id |> reduceSafely
That should get you what you're looking for. And hopefully it's also given you insight into the process of designing a functional solution to your problems.
P.S. I recommend the F# track at http://exercism.io/ if you want more practice in figuring out the functional approach to problem-solving. I learned a lot running through those exercises!
Im trying to check with a case if a list is empty rather then recursivly catching the pattern when it is, is this the right way to go in Erlang or am i just walking down the wrong path and pattern matching is the best way to catch if a list has been emptied or not?
calculate([Head|Tail], pi, x, y) ->
...calculations of Head being sent to a list...
case Tail == [] of
false ->
calculate(Tail, pi, x, y)
end.
or should i just pattern match on calculate if the list is empty?
Error in your code
General practice is to use function clause with pattern match. It works just as case, and it is considered to much more readable. And it fixes one error you have in your implementation:
First of all your code could be rewritten in this manner.
calculate([Head|Tail], pi, x, y) ->
%% ... actual calculations ...
calculate( Tail, pi, x, y);
calculate([], pi, x, y) ->
%% you need to return something here, but you don't
As you can see, one of clauses do not return anything, which is not allowed in Erlang (fail during compilation). Your implementation does exactly same thing. case just like anything in Erlang must return some value (and since it is lase statement in your function this value will be returned from function). And since case needs to return something, it needs to match on one of it's clauses. It most cases, since Tail == [] will return false it will not be a problem. But at last recursive call, when Tail is empty list, Tail == [] will return true and case will not match to anything. And in Erlang this will cause (throw, or exit to be exact) case_clause error. So your implementation will always fail.
To fix it you need to make sure you always have something matching in you case, like this
case Tail == [] of
false ->
calculate(Tail, pi, x, y)
true ->
%% return something
end.
Or it could be written like this
case Tail of
[] ->
%% return something sane
_ ->
calculate(Tail, pi, x, y)
end.
where _ will match to anything, and will work somewhat like else is some other languages. And finally it could be written with function clauses, just like I showed before, but with this sane value returned.
EDIT
returning a value
If you look closer at our code wright now we are returning only one value; the one from last recursive call (the one I called "sane"). If you would like to take under account all calculations from all recursive calls you need to accumulate them somehow. And to do this we will use Acc variable
calculate([Head|Tail], pi, x, y, Acc) ->
%% ... actual calculations with result assigned to Res variable ...
NewAcc = [Res | Acc]
calculate(Tail, pi, x, y, NewAcc);
calculate([], pi, x, y, Acc) ->
Acc.
In each recursive call we add our calculations Res to accumulator Acc, and send this updated list to next level of recursion. And finally, when our input list is empty (we processed all data) we just return whole accumulator. All we need to do, is make sure, that when calculate is being first called, it is called with empty list as Acc. This could be done by new (somewhat old) function
calculate(List, pi, x, y) ->
calculate(List, pi, x, y, _Acc = []).
Now we can export calculate/4 and keep calculate/5 private.
Pattern match. Its the Right Thing.
It is also more efficient. It also prevents you from developing a habit of just accepting any sort of variables up front, going partway through your function and discovering that what you've received isn't even a list (oops!). Pattern matching (and using certain types of guards) are also central to the way Dialyzer checks success typings -- which may or not matter to you right now, but certainly will once you start working on the sort of software that has customers.
Most importantly, though, learning to take advantage of pattern matching teaches you to write smaller functions. Writing a huge function with a bajillion parameters that can do everything is certainly possible, and even common in many other languages, but pattern matching will illustrate to you why this is a bad idea as soon as you start writing your match cases. That will help you in ways I can't even begin to describe; it will seep into how you think about programs without you appreciating it at first; it will cut the clutter out of your nested conditions (because they won't exist); it will teach you to stop writing argument error checking code everywhere.
add a clause with empty list, and if not possible, one with a single element list:
func([H],P,X,Y) ->
do_something(H,P,X,Y);
func([H|T],P,X,Y) ->
do_something(H,P,X,Y),
func(T,P,X,Y).
Note that this will fail with an empty input list.
Look also if you can use one of the functions lists:map/2 or lists:foldl/3 or list comprehension...
I'm a completely new to erlang. As an exercise to learn the language, I'm trying to implement the function sublist using tail recursion and without using reverse. Here's the function that I took from this site http://learnyousomeerlang.com/recursion:
tail_sublist(L, N) -> reverse(tail_sublist(L, N, [])).
tail_sublist(_, 0, SubList) -> SubList;
tail_sublist([], _, SubList) -> SubList;
tail_sublist([H|T], N, SubList) when N > 0 ->
tail_sublist(T, N-1, [H|SubList]).
It seems the use of reverse in erlang is very frequent.
In Mozart/Oz, it's very easy to create such the function using unbound variables:
proc {Sublist Xs N R}
if N>0 then
case Xs
of nil then
R = nil
[] X|Xr then
Unbound
in
R = X|Unbound
{Sublist Xr N-1 Unbound}
end
else
R=nil
end
end
Is it possible to create a similar code in erlang? If not, why?
Edit:
I want to clarify something about the question. The function in Oz doesn't use any auxiliary function (no append, no reverse, no anything external or BIF). It's also built using tail recursion.
When I ask if it's possible to create something similar in erlang, I'm asking if it's possible to implement a function or set of functions in erlang using tail recursion, and iterating over the initial list only once.
At this point, after reading your comments and answers, I'm doubtful that it can be done, because erlang doesn't seem to support unbound variables. It seems that all variables need to be assigned to value.
Short Version
No, you can't have a similar code in Erlang. The reason is because in Erlang variables are Single assignment variables.
Unbound Variables are simply not allowed in Erlang.
Long Version
I can't imagine a tail recursive function similar to the one you presenting above due to differences at paradigm level of the two languages you are trying to compare.
But nevertheless it also depends of what you mean by similar code.
So, correct me if I am wrong, the following
R = X|Unbound
{Sublist Xr N-1 Unbound}
Means that the attribution (R=X|Unbound) will not be executed until the recursive call returns the value of Unbound.
This to me looks a lot like the following:
sublist(_,0) -> [];
sublist([],_) -> [];
sublist([H|T],N)
when is_integer(N) ->
NewTail = sublist(T,N-1),
[H|NewTail].
%% or
%%sublist([H|T],N)
%% when is_integer(N) -> [H|sublist(T,N-1)].
But this code isn't tail recursive.
Here's a version that uses appends along the way instead of a reverse at the end.
subl(L, N) -> subl(L, N, []).
subl(_, 0, Accumulator) ->
Accumulator;
subl([], _, Accumulator) ->
Accumulator;
subl([H|T], N, Accumulator) ->
subl(T, N-1, Accumulator ++ [H]).
I would not say that "the use of reverse in Erlang is very frequent". I would say that the use of reverse is very common in toy problems in functional languages where lists are a significant data type.
I'm not sure how close to your Oz code you're trying to get with your "is it possible to create a similar code in Erlang? If not, why?" They are two different languages and have made many different syntax choices.