148 lines
3.3 KiB
Elixir
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
|