I have a piece of code that goes like this:
Fi_F = fun (F, I, Xs) ->
fun ( X ) ->
F( x_to_list(X, Xs, I) )
end
end,
I just need to turn a function of list to a function of one number. For example with Xs = [1,2,3] and I = 2, I expect this to grant me with function:
fun ( X ) -> F([ 1, X, 3]) end.
But somehow F, I and X are shadowed, not closured, so it fails in x_to_list with an empty list.
I'm still new to Erlang and think I'm missing something more conceptual, than a mere syntax problem.
UPD: Found a bug. I wrote x_to_list/3 this way:
x_to_list( X, L, I ) ->
lists:sublist(L, I) ++ [ X ] ++ lists:nthtail(I+1, L).
So it counts list elements from 0, not 1. When I call it with I = 3, it fails. So this is not about closuring.
I still have shadowing warnings though, but it is completely another issue.
A somewhat quick and dirty implementation of x_to_list/3 (just to test) would be:
x_to_list(X, Xs, I) ->
{ Pre, Post } = lists:split(I-1, Xs),
Pre ++ [X] ++ tl(Post).
Then, your code works without problems:
> Q = fun ( F, I, Xs ) -> fun (X) -> F( x_to_list(X, Xs, I)) end end.
> Y = Q( fun(L) -> io:format("~p, ~p, ~p~n", L) end, 2, [1,2,3] ).
> Y(4).
1, 4, 3
ok
Related
-module(tut).
-export([main/0]).
main() ->
folders("C:/Users/David/test/").
folders(PATH) ->
{_,DD} = file:list_dir(PATH),
A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
% R is a list of all folders inside PATH
R = [PATH++X|| {X,Y} <- A, Y =:= true],
io:fwrite("~p~n", [R]),
case R of
[] -> ok;
% How call again folders function with the first element of the list?
% And save the result in some kind of structure
end.
Sorry for the beginner question, but I'm still new to Erlang. I would like to know how I can call the function again until saves the results in a kind of list, tuple or structure...
Like:
[
{"C:/Users/David/test/log",
{"C:/Users/David/test/log/a", "C:/Users/David/test/log/b"}},
{"C:/Users/David/test/logb",
{"C:/Users/David/test/logb/1", "C:/Users/David/test/logb/2","C:/Users/David/test/logb/3"}},
]
Few things:
These 2 calls can be simplified.
A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
R = [PATH++X|| {X,Y} <- A, Y =:= true],
into
A = [H || H <- DD, filelib:is_dir(PATH ++ H) =:= true],
In terms of representation, sub-folders should be in list format, not tuple. It will be difficult to work with if they were tuples.
Sample structure: {Folder, [Subfolder1, Subfolder2, ...]}, where SubfolderX will have the same definition and structure, recursively.
Folders are like tree, so need to have recursive call here. Hope you are already familiar with the concept. Below is one way to do it using list comprehension - there are other ways anyway, e.g. by using lists:foldl function.
folders(PATH) ->
{_, DD} = file:list_dir(PATH),
A = [H || H <- DD, filelib:is_dir(PATH ++ "/" ++ H) =:= true],
%%io:format("Path: ~p, A: ~p~n", [Path, A]),
case A of
[] -> %%Base case, i.e. folder has no sub-folders -> stop here
{PATH, []};
_ -> %%Recursive case, i.e. folder has sub-folders -> call #folders
{PATH, [folders(PATH ++ "/" ++ H2) || H2 <- A]}
end.
For consistency reason, you need to call the main function without a forward slash at the end, as this will be added in the function itself.
Folders = folders("C:/Users/David/test"). %% <- without forward slash
A helper function pretty_print below can be used to visualize the output on the Erlang shell
Full code:
-export([folders/1]).
-export([main/0]).
main() ->
Folders = folders("C:/Users/David/test"),
pretty_print(Folders, 0),
ok.
folders(PATH) ->
{_, DD} = file:list_dir(PATH),
A = [H || H <- DD, filelib:is_dir(PATH ++ "/" ++ H) =:= true], %%please note the "/" is added here
%%io:format("Path: ~p, A: ~p~n", [Path, A]),
case A of
[] -> %%Base case, i.e. folder has no sub-folders -> stop here
{PATH, []};
_ -> %%Recursive case, i.e. folder has sub-folders -> call #folders
{PATH, [folders(PATH ++ "/" ++ H2) || H2 <- A]}
end.
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].
I would like to use the below Erlang code to get the highest integer in a list of integers but for some reason always end up getting the last integer in the list. Any help?
Solution example -> test:max([2,8,5,6]). should return 8 but with this code it returns 6.
-spec max(L) -> M when
L::[integer()],
M::integer().
max([H | T]) ->
F = fun(L, Acc) -> max([L]) end,
lists:foldl(F, H, T).
Your function F should return the max of L and Acc. You can use the builtin max/2 function for that:
...
F = fun(L, Acc) -> max(L, Acc) end.
...
Test:
1> F = fun(L, Acc) -> max(L, Acc) end.
#Fun<erl_eval.12.52032458>
2> [H | T] = [2, 8, 5, 6].
[2,8,5,6]
3> lists:foldl(F, H, T).
8
What you return in your function F will be the new value of Acc, and eventually the value lists:foldl/3 will return.
What you may want to do is do comparison inside F and check if Acc is greater than the current value. You don't need to recurse max/1 since you're iterating the list in lists:foldl/3 anyway.
Let me know if you need the actual code right away, but I would recommend figuring it out yourself. It's more fun for you that way.
I'm trying to make a sumif function in Erlang that would return a sum of all elements in a list if the predicate function evaluates to true. Here is what I have:
sumif(_, []) -> undefined;
sumif(Fun, [H|T]) -> case Fun(H) of
true -> H + sumif(Fun, T);
false -> sumif(Fun, T)
end.
I also implemented my own pos function which returns true if a number is greater than 0 and false otherwise:
pos(A) -> A > 0.
I tried using pos with sumif but I'm getting this error:
exception error: bad function pos
Why is this happening? Is it because of my sumif function or pos? I have tested pos on its own and it seems to work just fine.
Edit: It might be because how I'm calling the function. This is how I'm currently calling it: hi:sumif(pos,[-1,1,2,-3]). Where hi is my module name.
Is it because of my sumif function or pos?
It's because of sumif. You should return 0 when an empty list is passed, as it'll be called from the 2nd clause when T is []:
-module(a).
-compile(export_all).
sumif(_, []) -> 0;
sumif(Fun, [H|T]) -> case Fun(H) of
true -> H + sumif(Fun, T);
false -> sumif(Fun, T)
end.
pos(A) -> A > 0.
Test:
1> c(a).
{ok,a}
2> a:sumif(fun a:pos/1, [-4, -2, 0, 2, 4]).
6
List comprehensions make things far simpler:
sumif(F, L) ->
lists:sum([X || X <- L, F(X)]).
Dobert's answer is of cousrse right, problem is your sum for empty list.
If your concern is performance a little bit you should stick to tail recursive solution (in this case it matter because there is not lists:reverse/1 involved).
sumif(F, L) ->
sumif(F, L, 0).
sumif(F, [], Acc) when is_function(F, 1) -> Acc;
sumif(F, [H|T], Acc) ->
New = case F(H) of
true -> H+Acc;
false -> Acc
end,
sumif(F, T, New).
Ways how to make correct function for first parameter:
F1 = fun pos/1, % inside module where pos/1 defined
F2 = fun xyz:pos/1, % exported function from module xyz (hot code swap works)
N = 0,
F3 = fun(X) -> X > N end, % closure
% test it
true = lists:all(fun(F) -> is_function(F, 1) end, [F1, F2, F3]).
There has tow error in your code:
1. sumif(_, []) -> undefined; should return 0, not undefined.
2. when you pass pos(A) -> A > 0. to sumif/2,you should use fun pos/1, please read http://erlang.org/doc/programming_examples/funs.html#id59138
sumif(F, L) ->
lists:foldl(fun(X, Sum) when F(X) -> Sum+X; (_) -> Sum end, 0, L).
You can use lists:foldl.
I have a {H,VV} pair and I want to compare this pair against the rest of the Map to find other key that has the same value.
I tried this:
check(H,Map)->
VV=maps:get(H,Map),
Fun = fun(K,V) when H =/= K, V=:=VV->
io:format("~p~p~n",[H,K])
end,
maps:map(Fun,Map).
it compiles but raise error "function_clause"
Any ideas how to implement this?
The function you're passing to maps:map/2 does not handle the H key nor any value not equal to VV. Try this instead:
check(H,Map)->
VV=maps:get(H,Map),
Fun = fun(K,V) when H =/= K, V=:=VV->
io:format("~p:~p~n",[H,K]),
V;
(_,V) -> V
end,
maps:map(Fun,Map).
I think you're better off using maps:fold/3 for this case, though, since you're not trying to create a new map, but rather just want to know the other keys with the same value as H. Consider the approach below:
check(H, Map) ->
VV = maps:get(H,Map),
maps:fold(fun(K,V,Acc) when K /= H, V =:= VV ->
[K|Acc];
(_,_,Acc) ->
Acc
end, [], Map).
This version returns a list of keys that have the same value as H in Map.
There are list comprehension solutions for this as well:
VV = maps:get(H,Map),
[ K || K <- maps:keys(Map), K =/= H, VV =:= maps:get(K, Map) ].
Or
VV = maps:get(H,Map),
[ K || {K, V} <- maps:to_list(Map), K =/= H, V =:= VV ].
How to represent this clause in one line using Fun.
perms([]) -> [[]];
perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].
I believe what you are seeking is for a fun to be "self-recursive".
The fun syntax is not able to refer to itself inside the fun body, so one need to use a trick where the fun to call is a parameter. This is commonly referred to as the ycombinator.
Some example code will likely describe it better:
permutator() ->
fun
([], _F) ->
[[]];
(L, F) ->
[ [H|T] || H <- L, T <- F(L--[H], F)]
end.
do_permutate(L) ->
P = permutator(),
P(L, P).
As you can see this is quite awkward. If you just wanted to refer to the perms functions of yours, you can use the code: fun perms/1.
I also got another answer similar to Christian.
5> Perms = fun(X) -> Fun = fun([],F) -> [[]]; (L,F) -> [[H|T] || H <- L, T <- F(L--[H],F)] end, Fun(X, Fun) end.
#Fun<erl_eval.6.13229925>
6> Perms("cat").
["cat","cta","act","atc","tca","tac"]