Closed tjpalmer closed 5 months ago
Also for reference, if I try making a generic perform
:
fun perform(task: a): <console, env> int
really-perform(task)
I get this error:
dyn.kk(16, 3): error: no function really-perform is defined that matches the argument types
context : really-perform(task)
term : really-perform
inferred type: ($a, ...) -> ...
candidates : really-perform: (task : string) -> <console,env> int
really-perform: (task : list<string>) -> <console,env> int
I presume that's expected by y'all, but it shows an example wrong direction I've been down.
And I purposely made the function bodies for perform
and really-perform
exact copies for the two types.
With the latest koka you can do the following:
effect env
val mode: string
fun count(items: list<a>): int
items.length
fun perform(task: a, ?count: a -> int, ?show: a -> string): <console, env> int
println(mode ++ ": " ++ task.show)
task.count
fun with-mode(new-mode: string, action: () -> <env|e> a): e a
with val mode = new-mode
action()
fun main(): console ()
with val mode = "safe"
println(
perform("something").show ++ " " ++
with-mode("faster") { perform("reliable") }.show ++ " " ++
perform(["again"]).show
)
As far as this question goes:
// Why not this?
// fun with-mode(new-mode: string, action: () -> e a): <env|e> a
fun with-mode(new-mode: string, action: () -> <env|e> a): e a
The action requires the env
effect, but the body of with-mode
handles it, so with-mode
doesn't have to have any env
handler in it's context necessarily. Imagine them as exception handlers: the signature for with-env
says that action raises an error of type env
, and with-mode
handles that exception - it's not going to be caught any higher up. If with-mode
raised an exception (env
) prior to installing the handler for env
then it would also need env in it's context.
In your case you do have a handler outside of with-mode
all the time - which means the polymorphic type e
where you call with-mode
will be unified with env
and possibly more effects, but it isn't necessarily the case that you have to call with-mode
when there is already a handler outside of it. If you did want that to be the case you would use with override val mode = ...
.
I'm going to close this since the original issue is solved. If you have further questions or issues don't hesitate to create a new issue or a new discussion topic on the discussions tab.
Here's a sample program, and my question is how to avoid duplicating
perform
andreally-perform
for typesstring
andlist<string>
. Note thatwith-mode
properly abstracts over things, but it receives a callback for that.Bonus question in my TODO above. I expect to need to say that
with-mode
definitely uses effectenv
, since it sayswith val mode = ...
, but instead I'm required to put it on the callbackaction
, which surprises me.For further reference, this program is for comparison with other languages in this repo.