Last active
August 2, 2021 13:21
-
-
Save arsdragonfly/de89bc8e70b6f05a8e193ea183c6e4f2 to your computer and use it in GitHub Desktop.
Algebraic Interrupts (Effects) using Koka
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import std/num/random | |
| effect control eat-icecream() : () | |
| effect control check-cost() : int // returns the cost in int | |
| fun my-eat-icecream() { | |
| eat-icecream(); | |
| val cost = check-cost(); | |
| if (cost > 2) | |
| { | |
| return cost | |
| } | |
| else { | |
| eat-icecream(); | |
| return check-cost() | |
| } | |
| } | |
| fun lucky-draw() | |
| { | |
| with fun check-cost() { 0 } // initial cost | |
| with handler { | |
| return(x) {[x]} | |
| control eat-icecream() { | |
| val current-cost = check-cost(); | |
| val cost-lucky = { | |
| with override fun check-cost(){current-cost + 1} | |
| resume(()) | |
| }; | |
| val cost-unlucky = { | |
| with override fun check-cost(){current-cost + 3} | |
| resume(()) | |
| }; | |
| cost-lucky ++ cost-unlucky | |
| } | |
| } | |
| my-eat-icecream() | |
| } | |
| // fun lucky-draw() | |
| // { | |
| // var total-cost := 0; | |
| // with fun check-cost() { total-cost } | |
| // with handler { | |
| // return(x) {[x]} // transform the return value into a list | |
| // control eat-icecream() { | |
| // total-cost := total-cost + 1; | |
| // val cost-lucky = resume(()) | |
| // total-cost := total-cost - 1; | |
| // total-cost := total-cost + 3; | |
| // val cost-unlucky = resume(()) | |
| // total-cost := total-cost - 3; | |
| // cost-lucky ++ cost-unlucky // concatenate two lists | |
| // } | |
| // } | |
| // my-eat-icecream() | |
| // } | |
| fun buffet() { | |
| with fun eat-icecream() { () } // the eat-icecream handler does nothing | |
| with fun check-cost() { 2 } // the check-cost handler always returns 2 | |
| my-eat-icecream() | |
| } | |
| fun flat-pricing(price: int) { | |
| var total-cost := 0; | |
| with fun eat-icecream() { total-cost := total-cost + price } | |
| with fun check-cost() { total-cost } | |
| my-eat-icecream() | |
| } | |
| effect fun add-cost(cost: int) : () | |
| fun decreasing-pricing(price: int) { | |
| var current-price := price; | |
| with fun eat-icecream() { | |
| add-cost(current-price); | |
| if (current-price > 0) { | |
| current-price := current-price - 1 | |
| } | |
| } | |
| my-eat-icecream() | |
| } | |
| fun decreasing-pricing-full(price: int) { | |
| var total-cost := 0 | |
| with fun check-cost() { total-cost } | |
| with fun add-cost(price) { | |
| total-cost := total-cost + price | |
| } | |
| decreasing-pricing(price) | |
| } | |
| fun with-fbi() { | |
| var innocent := False; | |
| with control eat-icecream() { | |
| if (!innocent) { | |
| val is-suspect = choose(True, False) // toss a coin | |
| if ( is-suspect ) { | |
| println("🚓"); // no more ice-creams for you! | |
| return 0 // of course we won't charge you for any | |
| // ice-cream, if that matters to you | |
| } else { | |
| innocent := True; | |
| resume(()) // you can keep on eating ice-creams | |
| } | |
| } else { | |
| resume(()) // We already know that you're not a suspect | |
| } | |
| } | |
| with fun check-cost() { 2 } // buffet | |
| my-eat-icecream() | |
| } | |
| fun main() { | |
| println(buffet()); // prints 2 | |
| println(flat-pricing(1)); // prints 2, i.e. two $1 ice-creams | |
| println(flat-pricing(3)); // prints 3, i.e. a $3 ice-cream | |
| println(decreasing-pricing-full(2)); // prints 3, i.e. a $2 and a $1 ice-cream | |
| println(with-fbi()); // prints 0 or 2, depending on the cop's coin toss | |
| with total-cost = lucky-draw().foreach | |
| println(total-cost) // prints 2, 4, 6 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment