Last active
December 31, 2015 06:29
-
-
Save ToJans/7948100 to your computer and use it in GitHub Desktop.
An attempt for proper Enumerators in Elixir
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Seqable do | |
defprotocol ChuckNorris do | |
def value?(continuation) | |
def value(continuation) | |
def next(continuation) | |
end | |
defimpl ChuckNorris, for: List do | |
def value?([]), do: false | |
def value?(_), do: true | |
def value([]), do: :undefined | |
def value(l), do: hd(l) | |
def next(l), do: tl(l) | |
end | |
defrecord Continuation, done: false, source: [], value: :undefined | |
def get_next(stream, modifier//fn x-> x end) do | |
done = ChuckNorris.value?(stream)==false | |
value = ChuckNorris.value(stream) | |
next_source = ChuckNorris.next(stream) | |
new_source = fn() -> modifier.(next_source) end | |
Continuation[done: done, source: new_source, value: value] | |
end | |
defimpl ChuckNorris, for: Continuation do | |
def value?(continuation), do: continuation.done == false | |
def value(continuation), do: continuation.value | |
def next(continuation=Continuation[done: true]), do: continuation | |
def next(continuation=Continuation[source: source]) do | |
case is_function(source) do | |
false -> Seqable.get_next(continuation.source) | |
true -> continuation.source.() | |
end | |
end | |
end | |
defimpl Enumerable, for: Continuation do | |
def count(cont), do: count(cont, 0) | |
defp count(Continuation[done: true], n), do: n | |
defp count(cont, n), do: count(ChuckNorris.next(cont), n+1) | |
def member?(cont, what), do: throw :not_implemented | |
def reduce(cont, acc, func) do | |
IO.inspect([cont, acc, func]) | |
case ChuckNorris.value?(cont) do | |
false -> acc | |
true -> | |
val = ChuckNorris.value(cont) | |
new_acc = func.(val, acc) | |
reduce(ChuckNorris.next(cont), new_acc, func) | |
end | |
end | |
end | |
def start(_type, _args), do: {:ok, self} | |
def filter(stream,func) do | |
case ChuckNorris.value?(stream) do | |
false -> Continuation[done: true, source: stream, value: :undefined] | |
true -> | |
case func.(ChuckNorris.value(stream)) do | |
true -> get_next(stream,&(filter(&1,func)) ) | |
false -> filter(ChuckNorris.next(stream),func) | |
end | |
end | |
end | |
def take(stream,0) do | |
Continuation[done: true, source: stream, value: :undefined] | |
end | |
def take(stream, n) do | |
case ChuckNorris.value?(stream) do | |
false -> Continuation[done: true, source: stream, value: :undefined] | |
true -> get_next(stream, &(take(&1,n-1))) | |
end | |
end | |
def skip(stream, 0) do | |
stream | |
end | |
def skip(stream, n) do | |
case ChuckNorris.value?(stream) do | |
false -> stream | |
true -> skip(ChuckNorris.next(stream),n-1) | |
end | |
end | |
defrecord CompositeChuckNorris, streams: [] | |
defimpl ChuckNorris, for: CompositeChuckNorris do | |
def value?(CompositeChuckNorris[streams: []]), do: false | |
def value?(CompositeChuckNorris[streams: [current|_]]), do: ChuckNorris.value?(current) | |
def value(CompositeChuckNorris[streams: []]), do: :undefined | |
def value(CompositeChuckNorris[streams: [current|_]]), do: ChuckNorris.value(current) | |
def next(c = CompositeChuckNorris[streams: []]), do: c | |
def next(CompositeChuckNorris[streams: [c]]), do: ChuckNorris.next(c) | |
def next(CompositeChuckNorris[streams: [current|next]]) do | |
n = ChuckNorris.next(current) | |
case ChuckNorris.value?(n) do | |
false -> ChuckNorris.next(CompositeChuckNorris[streams: next]) | |
true -> CompositeChuckNorris[streams: next ++ [current]] | |
end | |
end | |
end | |
def interleave(streams) do | |
CompositeChuckNorris[streams: streams] | |
end | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ExUnit.start | |
defmodule ChuckNorrisTest do | |
use ExUnit.Case | |
test "list" do | |
list = [1, 2, 3, 4, 5] | |
list2 = [:a, :b] | |
assert 15 == Enum.reduce(list, 0, &add_numbers/2) | |
assert [1, 3, 5] == Enum.to_list(Seqable.filter(list, &odd/1)) | |
assert [1, 2, 3] == Enum.to_list(Seqable.take(list, 3)) | |
assert [3, 4, 5] == Enum.to_list(Seqable.skip(list, 2)) | |
#assert [:a,1,:b,2,3,4,5] == Enum.to_list(Seqable.interleave([list2,list])) | |
end | |
defp add_numbers(a,b), do: a+b | |
defp odd(x), do: rem(x,2) == 1 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment