Reader effect - access an immutable environment value.
Supports both simple single-context usage and multiple independent contexts via tags.
Tag Convention
Tags should be module atoms — either the effect module itself (Reader)
for singleton context, or a derived atom (MyApp.Config, Reader.DB)
for namespaced contexts. Module atoms are globally unique by construction,
eliminating accidental collisions between independent pieces of context.
Simple Usage (default tag)
use Skuld.Syntax
alias Skuld.Effects.Reader
comp do
cfg <- Reader.ask()
cfg.name
end
|> Reader.with_handler(%{name: "alice"})
|> Comp.run!()
#=> "alice"Multiple Contexts (explicit tags)
comp do
db <- Reader.ask(:db)
api <- Reader.ask(:api)
{db.host, api.url}
end
|> Reader.with_handler(%{host: "localhost"}, tag: :db)
|> Reader.with_handler(%{url: "https://api.example.com"}, tag: :api)
|> Comp.run!()
#=> {"localhost", "https://api.example.com"}Per-tag dispatch
Each tag gets its own handler sig (a module atom) and compact operation atom. The tag is encoded in the sig, not in the operation args:
ask→Comp.effect(sig(tag), Reader.Ask)— bare atom, zero allocation
Summary
Functions
Install Reader handler via catch clause syntax.
Read and apply a function to the environment value.
Extract the context value for the given tag from an env
Run a computation with a modified environment value.
Install a scoped Reader handler for a computation.
Functions
Install Reader handler via catch clause syntax.
Accepts either value or {value, opts}:
catch
Reader -> %{config: true}
Reader -> {%{config: true}, tag: :my_reader}
@spec asks((term() -> term())) :: Skuld.Comp.Types.computation()
Read and apply a function to the environment value.
Examples
Reader.asks(&Map.get(&1, :name)) # use default tag
Reader.asks(:user, &Map.get(&1, :name)) # use explicit tag
@spec asks(atom(), (term() -> term())) :: Skuld.Comp.Types.computation()
@spec get_context(Skuld.Comp.Types.env(), atom()) :: term()
Extract the context value for the given tag from an env
@spec local((term() -> term()), Skuld.Comp.Types.computation()) :: Skuld.Comp.Types.computation()
Run a computation with a modified environment value.
Examples
Reader.local(&Map.put(&1, :debug, true), comp) # use default tag
Reader.local(:config, &Map.put(&1, :debug, true), comp) # use explicit tag
@spec local(atom(), (term() -> term()), Skuld.Comp.Types.computation()) :: Skuld.Comp.Types.computation()
@spec with_handler(Skuld.Comp.Types.computation(), term(), keyword()) :: Skuld.Comp.Types.computation()
Install a scoped Reader handler for a computation.
Options
tag- the context tag (default:Skuld.Effects.Reader)
Examples
# Simple usage with default tag
comp do
cfg <- Reader.ask()
cfg.name
end
|> Reader.with_handler(%{name: "alice"})
|> Comp.run!()
#=> "alice"
# With explicit tag
comp do
db <- Reader.ask(:db)
db.host
end
|> Reader.with_handler(%{host: "localhost"}, tag: :db)
|> Comp.run!()
#=> "localhost"
# Multiple contexts
comp do
db <- Reader.ask(:db)
cache <- Reader.ask(:cache)
{db, cache}
end
|> Reader.with_handler(%{host: "db.local"}, tag: :db)
|> Reader.with_handler(%{host: "cache.local"}, tag: :cache)
|> Comp.run!()
#=> {%{host: "db.local"}, %{host: "cache.local"}}