Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification on Algae.Free usage #72

Open
florius0 opened this issue Jan 25, 2022 · 1 comment
Open

Clarification on Algae.Free usage #72

florius0 opened this issue Jan 25, 2022 · 1 comment

Comments

@florius0
Copy link

florius0 commented Jan 25, 2022

Im not sure if issues is a correct place to request help, however I'm trying to understand Algae.Free and it isn't as easy as it might be

There is link to an article on free monads in docs

I tried to implement Haskell code in Elixir, and here's what I've got:

import Algae
import TypeClass
use Witchcraft

defmodule Toy do
  defsum do
    defdata Output do
      output :: any()
      next :: any()
    end

    defdata Bell do
      next :: any()
    end

    defdata(Done :: none())
  end


  defimpl TypeClass.Property.Generator, for: Toy.Output do
    def generate(_) do
      [1, 1.1, "", :a]
      |> Enum.random()
      |> Toy.Output.new()
    end
  end

  defimpl TypeClass.Property.Generator, for: Toy.Bell do
    def generate(_) do
      [1, 1.1, "", :a]
      |> Enum.random()
      |> Toy.Bell.new()
    end
  end

  defimpl TypeClass.Property.Generator, for: Toy.Done do
    def generate(_), do: Toy.Done.new()
  end

  definst Witchcraft.Functor, for: Toy.Output do
    def map(%{output: output, next: next}, fun), do: %Toy.Output{output: output, next: fun.(next)}
  end

  definst Witchcraft.Functor, for: Toy.Bell do
    def map(%{next: next}, fun), do: %Toy.Bell{next: fun.(next)}
  end

  definst Witchcraft.Functor, for: Toy.Done do
    def map(_, _), do: %Toy.Done{}
  end

  def of4(_, x) do
    Algae.Free.new(x ~> (&Algae.Free.Pure.new/1))
  end

  def output(x), do: fn y -> Algae.Free.new(Toy.Output.new(x, Algae.Free.Pure.new(y))) end

  def bell, do: fn y -> Algae.Free.new(Toy.Bell.new(Algae.Free.Pure.new(y))) end

  def done, do: Algae.Free.new(Toy.Done.new())

  def program do
    monad Algae.Free.new() do
      output(1)
      bell()
    end
  end
end

And here is the confusing moment Toy.program.(nil) returns %Algae.Free.Pure{pure: %Toy.Bell{next: %Algae.Free.Pure{pure: nil}}} instead of %Toy.Output{next: %Algae.Free.Pure{pure: %Toy.Bell{next: %Algae.Free.Pure{pure: nil}}}, output: 1}. It basically does not 'concatenate' previous value with the next one

Thanks in advance for your help!

@github-actions
Copy link

Thank you for submitting an issue! It means a lot that you took the time -- it helps us be better 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant