Skip to content

Instantly share code, notes, and snippets.

@christhekeele
Last active May 5, 2017 10:54
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christhekeele/8012622 to your computer and use it in GitHub Desktop.
Save christhekeele/8012622 to your computer and use it in GitHub Desktop.
Infinite Prime Generator in Elixir
# Elixir v1.0.2
defmodule Prime do
def stream do
Stream.unfold( [], fn primes ->
next = next_prime(primes)
{ next, [next | primes] }
end )
end
def take(n) when is_integer(n), do: Enum.take(stream, n)
def get(n) when is_integer(n), do: take(n) |> List.last
def up_to(n) when is_integer(n) do
stream
|> Stream.take_while(&(&1 < n))
|> Enum.to_list
end
defp next_prime([]), do: 2
defp next_prime(primes) when is_list primes do
primes |> next_primes(1) |> List.first
end
defp next_primes(primes, quantity) when is_list primes and is_integer quantity do
from = List.first(primes) + 1
integers(from)
|> Stream.drop_while(fn number ->
Enum.any?(primes, fn prime ->
rem(number, prime) == 0
end )
end )
|> Enum.take(quantity)
end
defp integers(n) when is_integer(n) do
Stream.iterate(n, &(&1+1))
end
defmodule Factor do
def list(1), do: [1]
def list(n) when is_integer(n) and n > 1,
do: n |> distribution |> list
def list(dict) when is_list(dict),
do: Dict.keys dict
def list({ :error, reason }),
do: { :error, reason }
def distribution(1), do: [{ 1, 1 }]
def distribution(n) when is_integer(n) and n > 1 do
case factorize(n) do
{ :halted, distribution } -> Enum.reverse distribution
{ :done, _ } -> { :error, "Ran out of prime numbers." }
{ :suspended, _ } -> { :error, "Couldn't get prime numbers."}
end
end
defp factorize(n),
do: Enumerable.reduce(Prime.stream, { :cont, { n, [] } }, &reducer/2)
defp reducer(_factor, { n, distribution }) when n == 1,
do: { :halt, distribution }
defp reducer(factor, { n, distribution }) when factor > n,
do: { :halt, distribution }
defp reducer(factor, { n, distribution }) do
result = case factor_down(n, factor) do
[] -> { n, distribution }
divisions -> { List.last(divisions), [{ factor, length(divisions) } | distribution] }
end
{ :cont, result }
end
defp factor_down(n, factor) do
Stream.iterate(n, &(div(&1, factor)))
|> Stream.take_while(&(rem(&1, factor) == 0))
|> Stream.map(&(div(&1, factor)))
|> Enum.to_list
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment