exercism/elixir/protein-translation/lib/protein_translation.ex

69 lines
2.0 KiB
Elixir

defmodule ProteinTranslation do
@doc """
Given an RNA string, return a list of proteins specified by codons, in order.
"""
@spec of_rna(String.t()) :: {:ok, list(String.t())} | {:error, String.t()}
def of_rna(""), do: {:ok, []}
def of_rna(rna) do
rna
|> String.graphemes()
|> Enum.chunk_every(3)
|> Enum.map(&Enum.join/1)
|> Enum.reduce_while([], &reducer/2)
|> case do
proteines when is_list(proteines) -> {:ok, Enum.reverse(proteines)}
{:error, error} -> {:error, error}
end
end
defp reducer(codon, proteines) do
case of_codon(codon) do
{:error, _error} -> {:halt, {:error, "invalid RNA"}}
{:ok, "STOP"} -> {:halt, proteines}
{:ok, proteine} -> {:cont, [proteine | proteines]}
end
end
@doc """
Given a codon, return the corresponding protein
UGU -> Cysteine
UGC -> Cysteine
UUA -> Leucine
UUG -> Leucine
AUG -> Methionine
UUU -> Phenylalanine
UUC -> Phenylalanine
UCU -> Serine
UCC -> Serine
UCA -> Serine
UCG -> Serine
UGG -> Tryptophan
UAU -> Tyrosine
UAC -> Tyrosine
UAA -> STOP
UAG -> STOP
UGA -> STOP
"""
@cysteines ~w(UGU UGC)
@leucines ~w(UUA UUG)
@tyrosines ~w(UAU UAC)
@phenylalanines ~w(UUU UUC)
@serines ~w(UCU UCC UCA UCG)
@methionines ~w(AUG)
@tryptophans ~w(UGG)
@stops ~w(UAA UAG UGA)
@spec of_codon(String.t()) :: {:ok, String.t()} | {:error, String.t()}
def of_codon(cysteine) when cysteine in @cysteines, do: {:ok, "Cysteine"}
def of_codon(leucine) when leucine in @leucines, do: {:ok, "Leucine"}
def of_codon(tyrosine) when tyrosine in @tyrosines, do: {:ok, "Tyrosine"}
def of_codon(phenylalanine) when phenylalanine in @phenylalanines, do: {:ok, "Phenylalanine"}
def of_codon(serine) when serine in @serines, do: {:ok, "Serine"}
def of_codon(methionine) when methionine in @methionines, do: {:ok, "Methionine"}
def of_codon(tryptophan) when tryptophan in @tryptophans, do: {:ok, "Tryptophan"}
def of_codon(stop) when stop in @stops, do: {:ok, "STOP"}
def of_codon(_invalid), do: {:error, "invalid codon"}
end