Elixir: recursive generators - recursion

Is it possible to build a Python style recursive generator with Elixir? Something like this:
def traverse(parent_dir):
dirs, files = get_dirs_and_files_as_lists(parent_dir)
for d in dirs:
yield from traverse(d)
for f in files:
yield f
For all the files to be processed linearly, without overhead implied by an eager list of indefinite length:
for f in traverse(dir):
process(f)
This, or some working equivalent, should be possible using streams; unfortunately, I have no idea how.
I want something like this, just lazy:
def traverse_eagerly(parent_dir) do
{dirs, files} = get_dirs_and_files_as_lists(parent_dir)
for x <- dirs do
traverse_eagerly(x)
end
|> Enum.concat()
|> Enum.concat(files)
end

The solution appears to be trivial: replace Enum with Stream.
def traverse_lazily(parent_dir) do
{dirs, files} = get_dirs_and_files_as_lists(parent_dir)
for x <- dirs do
traverse_lazily(x)
end
|> Stream.concat()
|> Stream.concat(files)
end
The following works as expected:
s = traverse_lazily(a_dir_of_choice)
for x <- s, do: whatever_you_please(x)
Very nice of the language. As fine a solution as you would wish for. Unless I'm missing something, that is :) . Comments are welcome!

You do not need Stream here, but if you want, here is it:
defmodule Traverse do
#spec traverse(root :: binary(), yielder :: (binary() -> any())) ::
:ok | {:error, posix()}
def traverse(root, yielder) do
# https://hexdocs.pm/elixir/master/File.html?#ls/1
with {:ok, list} <- File.ls(root) do
list
|> Stream.each(fn file_or_dir ->
if File.dir?(file_or_dir),
do: traverse(file_or_dir, yielder), # TCO
else: yielder.(file_or_dir)
end)
|> Stream.run()
end
end
end
And call it like:
Traverse.traverse(".", &IO.inspect/1)

Related

Writing a clean/cleaner solution to "Valid Anagram" in Elixir

Trying to level up my Elixir understanding by doing algo/leetCode style problems using Elixir.
As I'm a relatively new programmer (around a year in) and was trained on traditionally OOP languages like Ruby and JS, it's still somewhat hard for me to wrap my head around doing algo questions in a functional paradigm, though I felt I understood the Udemy course I took on Elixir/Phoenix.
I wrote a solution to the LeetCode "valid anagram" problem using Elixir and Repl and wanted to see if people had any ideas for improving/understanding the problem or if there was a best approach way of thinking for this problem.
For an answer, I'd take a code review, a book recommendation or even just suggestions of what I could do differently.
Thank you for your time and hope this (my first question on this site) is clear.
###
Given two strings s and t , write a function to determine if t is an anagram of s.
Example 1:
Input: s = "anagram", t = "nagaram"
Output: true
Example 2:
Input: s = "rat", t = "car"
Output: false
Note:
You may assume the string contains only lowercase alphabets.
###
defmodule Algos do
def is_anagram(str1, str2) do
case String.length(str1) == String.length(str2) do
false ->
IO.puts(false)
true ->
both_trackers(str1, str2)
|> check_trackers
|> IO.puts
end
end
def both_trackers(str1, str2) do
t1 = make_tracker(str1)
t2 = make_tracker(str2)
{t1, t2}
end
def check_trackers({t1, t2}) do
Map.keys(t1)
|> Enum.reduce_while(true, fn x, acc ->
if t1[x] == t2[x], do: {:cont, acc}, else: {:halt, false}
end)
end
def make_tracker(str) do
tracker = String.split(str, "", trim: true)
|> Enum.reduce(%{},
fn x,acc -> Map.merge(acc,
case !!acc[x] do
false ->
%{x => 1}
true ->
%{x => acc[x] + 1}
end
)
end
)
tracker
end
end
Algos.is_anagram("sloop ", "pools")
New elixir has Enum.frequencies, which generates a histogram from an enumerable, which basically solves this problem out of the box:
defmodule Algos do
def anagram?(a, b) do
Enum.frequencies(to_charlist(a)) == Enum.frequencies(to_charlist(b))
end
end
Algos.anagram?("a gentleman", "elegant man") # => true
Algos.anagram?("alice", "bob") # => false

How to count a number on in Elixir without built in function such as Enum.count?

How to count a number on in Elixir without built-in function such as Enum.count. Here is my code, Thanks so much
defmodule Ans do
#my_favorite_number 0
def sum([]) do
0
end
def sum([head|tail]) do
head + sum(tail)
end
def average([head|tail]) do
total = sum([head|tail])
iterations = Enum.count([head|tail])
output = total / iterations
end
end
You should read about tail-call optimization. The compiler makes use of this optimisation to prevent a new stack frame being created every recursive call, which will happen in your code. Here is an example of how to write the sum/1 function in a tail-recursive way. The main idea is to keep the return in an accumulator variable that is passed to each call, instead of building up the answer in the call stack:
def sum(list), do: sum(0, list)
def sum(acc, []), do: acc
def sum(acc, [head | tail]), do: sum(acc + head, tail)
For count, you can do something similar, but just add 1 instead of the value of the list item:
def count(list), do: count(0, list)
def count(acc, []), do: acc
def count(acc, [_head | tail]), do: count(acc + 1, tail)
While the answer by Adam is perfectly correct, to calculate the average you might do better (in one loop,) using more sophisticated accumulator.
defmodule M do
def avg(list), do: do_avg({0, 0}, list)
defp do_avg({cnt, sum}, []),
do: sum / cnt
defp do_avg({cnt, sum}, [h | t]),
do: do_avg({cnt + 1, sum + h}, t)
end
M.avg [1,2,3,4]
#⇒ 2.5
Here we do accumulate both count and total and calculate an average on the last step when the list is exhausted.
Also, you might return everything, as a tuple {cnt, sum, sum / cnt}, or as a map for better readability.

Testing recursive IO prompt in Elixir/Erlang

I have a function confirm, which reads IO input, and depending by input, if it's y (yes) or n (no), it returns true/false, otherwise it calls confirm again, until any expected y or n is entered.
#spec confirm(binary) :: boolean
def confirm(question) do
answer = question |> IO.gets() |> String.trim() |> String.downcase()
case(answer) do
"y" -> true
"n" -> false
_ -> confirm(question)
end
end
To test y and n cases it's easy:
assert capture_io([input: "y"], fn -> confirm("Question") end) == "Question"
But I have no idea how to capture IO multiple times to test recursive case, let's say if at first input is "invalid" and then "y". Does elixir has any way to test IO functions like this? Or maybe do you have some suggestions how I could rewrite function to test it easier?
Original question https://elixirforum.com/t/testing-recursive-io-prompt/3715
Thanks for the help.
Untested, but what about just using newline characters?
assert capture_io([input: "foo\nbar\ny"], fn -> confirm("Question") end) == "Question"

F# stop Seq.map when a predicate evaluates true

I'm currently generating a sequence in a similar way to:
migrators
|> Seq.map (fun m -> m())
The migrator function is ultimately returning a discriminated union like:
type MigratorResult =
| Success of string * TimeSpan
| Error of string * Exception
I want to stop the map once I encounter my first Error but I need to include the Error in the final sequence.
I have something like the following to display a final message to the user
match results |> List.rev with
| [] -> "No results equals no migrators"
| head :: _ ->
match head with
| Success (dt, t) -> "All migrators succeeded"
| Error (dt, ex) -> "Migration halted owing to error"
So I need:
A way to stop the mapping when one of the map steps produces an Error
A way to have that error be the final element added to the sequence
I appreciate there may be a different sequence method other than map that will do this, I'm new to F# and searching online hasn't yielded anything as yet!
I guess there are multiple approaches here, but one way would be to use unfold:
migrators
|> Seq.unfold (fun ms ->
match ms with
| m :: tl ->
match m () with
| Success res -> Some (Success res, tl)
| Error res -> Some (Error res, [])
| [] -> None)
|> List.ofSeq
Note the List.ofSeq at the end, that's just there for realizing the sequence. A different way to go would be to use sequence comprehensions, some might say it results in a clearer code.
The ugly things Tomaš alludes to are 1) mutable state, and 2) manipulation of the underlying enumerator. A higher-order function which returns up to and including when the predicate holds would then look like this:
module Seq =
let takeUntil pred (xs : _ seq) = seq{
use en = xs.GetEnumerator()
let flag = ref true
while !flag && en.MoveNext() do
flag := not <| pred en.Current
yield en.Current }
seq{1..10} |> Seq.takeUntil (fun x -> x % 5 = 0)
|> Seq.toList
// val it : int list = [1; 2; 3; 4; 5]
For your specific application, you'd map the cases of the DU to a boolean.
(migrators : seq<MigratorResult>)
|> Seq.takeUntil (function Success _ -> false | Error _ -> true)
I think the answer from #scrwtp is probably the nicest way to do this if your input is reasonably small (and you can turn it into an F# list to use pattern matching). I'll add one more version, which works when your input is just a sequence and you do not want to turn it into a list.
Essentially, you want to do something that's almost like Seq.takeWhile, but it gives you one additional item at the end (the one, for which the predicate fails).
To use a simpler example, the following returns all numbers from a sequence until one that is divisible by 5:
let nums = [ 2 .. 10 ]
nums
|> Seq.map (fun m -> m % 5)
|> Seq.takeWhile (fun n -> n <> 0)
So, you basically just need to look one element ahead - to do this, you could use Seq.pairwise which gives you the current and the next element in the sequence"
nums
|> Seq.map (fun m -> m % 5)
|> Seq.pairwise // Get sequence of pairs with the next value
|> Seq.takeWhile (fun (p, n) -> p <> 0) // Look at the next value for test
|> Seq.mapi (fun i (p, n) -> // For the first item, we return both
if i = 0 then [p;n] else [n]) // for all other, we return the second
|> Seq.concat
The only ugly thing here is that you then need to flatten the sequence again using mapi and concat.
This is not very nice, so a good thing to do would be to define your own higher-order function like Seq.takeUntilAfter that encapsulates the behavior you need (and hides all the ugly things). Then your code could just use the function and look nice & readable (and you can experiment with other ways of implementing this).

tail recursive call in elixir and default parameters

I am writing a simple example in Elixir and although it works I don't really understand how.
defmodule MyList do
def sum([],acc \\ 0), do: acc
def sum([head | tail], acc), do: sum(tail,acc + head)
end
When I call MyList.sum I get the expected result
sum([]) => 0
sum([1,2,3]) => 6
I cannot add a default param in the second sum because the compiler throws an error
def sum/2 has default values and multiple clauses, use a separate clause for declaring defaults
So my question is, how come sum([1,2,3]) works? It does not match any of the definitions.
Is the function still tail recursive?
When you have a multiclause with optional arguments, you can specify defaults as a body-less clause:
defmodule MyList do
def sum(list, acc \\ 0) # sets up default arguments
def sum([],acc), do: acc
def sum([head | tail], acc), do: sum(tail,acc + head)
end
Regarding your example, I'm just guessing, but I think that your code amounts to something like following:
defmodule MyList do
# implicitly generated due to default argument
def sum(list), do: sum(list, 0)
def sum([],acc), do: acc
def sum([head | tail], acc), do: sum(tail,acc + head)
end
Which is why sum([1,2,3]) works as well.
Edit:
The function is definitely tail recursive. If the last thing a function does is a call of another function (or itself), then it is a tail call. So in this case, when we call sum(tail, acc + head), first the arguments are calculated, and then a tail recursive call happens.

Resources