Packages

A Markov chain text generator for Elixir.

Current section

Files

Jump to
faust lib faust.ex
Raw

lib/faust.ex

defmodule Faust do
@moduledoc """
A Markov chain text generator for Elixir
This module handles markov chain generation and traversing
"""
# Public API
@doc """
Generates a markov chain from a bitstring using `order` sized terms
Returns a markov transition table as a `Map`
"""
@spec generate_chain(binary, number) :: {:ok, term}
def generate_chain(bin, order),
do: {:ok, Faust.Table.generate(bin, order)}
@doc """
Returns the resulting string from traversing a markov chain `n` times
If a vertex is not found at any point in traversal it will return a partial result
"""
@spec traverse(term, number) :: {:ok, binary} | {:error, atom}
def traverse(chain, n),
do: traverse(chain, n, :default)
@doc """
Returns the resulting string from traversing a markov chain `n` times.
Traversal is guided by a specified `method` which is function that decides
which transitions to follow.
If a vertex is not found at any point in traversal it will return a partial result
"""
@spec traverse(term, number, fun) :: {:ok, binary} | {:error, atom}
def traverse(chain, n, method) do
cond do
is_function(method, 1) ->
do_traverse(chain, n, method)
method == :default ->
do_traverse(chain, n, &random/1)
true ->
{:error, :bad_method}
end
end
# Helpers
defp random(edges) do
x = :random.uniform
inspect(edges)
{edge, _} =Enum.min_by(edges, fn {_, prob} -> prob-x end)
edge
end
defp do_traverse(chain, n, method) do
start_seq = chain |> Map.keys |> Enum.random
do_traverse(chain, n, method, start_seq, Enum.join(start_seq, " "))
end
defp do_traverse(_, 0, _, _, acc) do
{:ok, acc}
end
defp do_traverse(chain, n, method, seq, acc) do
case chain[seq] do
nil -> {:ok, acc}
edges ->
term = method.(edges)
nseq = List.delete_at(seq, 0) ++ [term]
do_traverse(chain, n-1, method, nseq, Enum.join([acc, term], " "))
end
end
end