elixir-book/maps/myenum.exs

148 lines
3.3 KiB
Elixir

defmodule MyEnum do
# all?/1
# Returns true if all elements in enumerable are truthy.
def all?([head | tail]) do
# head truthy and all tail
head != false and head != nil and all?(tail)
all?([head | tail], fn elem -> elem != false and elem != nil end)
end
def all?([]) do
all?([], nil)
end
def all?([head | tail], fun) do
fun.(head) and all?(tail, fun)
end
def all?([], _fun) do
true
end
# each/2
# Invokes the given fun for each element in the enumerable.
def each([head | tail], fun) do
fun.(head)
each(tail, fun)
end
def each([], _fun) do
:ok
end
# Filters the enumerable, i.e. returns only those elements for which fun returns a truthy value.
def filter([], _fun) do
# do nothing -> This is wrong. Return an empty array instead.
[]
end
# filter using if ... do ... else ... end
def filter([head | tail], fun) do
if fun.(head) do
[head | filter(tail, fun)]
else
filter(tail, fun)
end
end
# I gave up on these two.
# split
# take
end
defmodule MyList do
def flatten([]) do
[]
end
def flatten([head | tail]) do
# this is basically the recursion
flatten(head) ++ flatten(tail)
end
def flatten(head) do
# if there's only on element, we make a list out of it, so that we can concat them
[head]
end
end
defmodule MyStream do
def squared(n), do: n * n
def iterate() do
# Stream.iterate/2 takes a start value x and a function f
# It then applies the function to the start value. And then it applies the function to f(x). And
# then to f(f(x)) until it stops.
# squared = fn n -> n*n end
Stream.iterate(2, &squared/1)
# How can I use a named function here? -> Use a &name/arity
|> Enum.take(5)
end
def fibonacci_unfold({f1, f2}) do
# first return-value of the tuple is the calculated state, second value is the next input
{f1, {f2, f1 + f2}}
end
def unfold() do
# more general, but related to iterate
# Each value is some function of the previous state.
# You calculate this rounds result and provide the next value
# function is of form:
# fn state -> {stream_value, new_state}
seed = {0, 1}
Stream.unfold(seed, &fibonacci_unfold/1)
|> Enum.take(15)
end
def read_lines(number_of_lines) do
start_fun = fn -> File.open!("/Users/nathan/tmp/text.ex") end
next_fun = fn file ->
case IO.read(file, :line) do
data when is_binary(data) -> {[data], file}
_ -> {:halt, file}
end
end
after_fun = fn file -> File.close(file) end
Stream.resource(start_fun, next_fun, after_fun)
|> Enum.take(number_of_lines)
|> IO.puts()
# Stream.resource/3 is useful to stream values from resources (files, time, etc.)
end
end
defmodule Countdown do
def sleep(seconds) do
receive do
after seconds * 1000 -> nil
end
end
def next(0) do
# looks at the time left
{:halt, 0}
end
def next(n) do
# sleep for a second
sleep(1)
{[inspect(n)], n-1}
end
def start() do
{_h, _m, s} = :erlang.time
# why is this nil???? This method was never invoked as I had defined it twice (there was a warning but I ignored it.)
60 - s - 1
end
def timer do
Stream.resource(&start/0, &next/1, fn _ -> nil end)
end
end