https://github.com/jechol/defr
defr is def for Witchcraft's Reader monads.
https://github.com/jechol/defr
Last synced: 6 months ago
JSON representation
defr is def for Witchcraft's Reader monads.
- Host: GitHub
- URL: https://github.com/jechol/defr
- Owner: jechol
- License: other
- Created: 2021-07-30T06:55:32.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2024-05-02T21:15:49.000Z (about 2 years ago)
- Last Synced: 2025-10-10T19:36:26.725Z (8 months ago)
- Language: Elixir
- Homepage:
- Size: 291 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
[](https://github.com/trevorite/defr/actions)
[](https://hex.pm/packages/defr)
[](https://github.com/trevorite/defr/blob/master/LICENSE.md)
`defr` is `def` for Witchcraft's Reader monads.
## Installation
The package can be installed by adding `defr` to your list of dependencies
in `mix.exs`:
```elixir
def deps do
[{:defr, "~> 0.3"}]
end
```
To format `defr` like `def`, add following to your `.formatter.exs`
```elixir
locals_without_parens: [defr: 2]
```
## `defr` transformation
```elixir
defmodule Target do
use Defr
import Enum, only: [at: 2]
defr top(list) do
list |> List.flatten() |> inject() |> middle() |> run()
end
defr middle(list) do
list |> bottom() |> inject() |> run()
end
defrp bottom(list) do
%{pos: pos} <- ask()
let _ = Process.sleep(100) # Use `let` to call non-reader function.
list |> at(pos) |> inject()
end
end
```
becomes (simplified for clarity)
```elixir
defmodule Target do
def top(list) do
monad(%Algae.Reader{}) do
env <- Algae.Reader.ask()
return(
list
|> Map.get(env, &List.flatten/1, &List.flatten/1).()
|> middle()
|> Reader.run(env)
)
end
end
def middle(list) do
monad %Algae.Reader{} do
env <- Algae.Reader.ask()
let _ = Process.sleep(100)
return(
list
|> Map.get(env, &Target.bottom/1, &Target.bottom/1).()
|> Reader.run(env)
)
end
end
defp bottom(list) do
monad %Algae.Reader{} do
env <- Algae.Reader.ask()
%{pos: pos} <- Algae.Reader.ask()
return(
list
|> Map.get(env, &Enum.at/2, &Enum.at/2).(pos)
)
end
end
end
```
## Test
```elixir
test "defr" do
assert 1 == Target.top([[0], 1]) |> Reader.run(%{pos: 1})
assert 20 ==
Target.top([[0], 1]) |> Reader.run(mock(%{&List.flatten/1 => [10, 20, 30], pos: 1}))
assert :imported_func ==
Target.top([[0], 1]) |> Reader.run(mock(%{&Enum.at/2 => :imported_func, pos: 1}))
assert :private_func ==
Target.top([[0], 1])
|> Reader.run(mock(%{&Target.bottom/1 => :private_func}))
end
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE.md) file for details