Skip to content

Instantly share code, notes, and snippets.

@Octachron
Last active February 14, 2025 14:16
Show Gist options
  • Save Octachron/6a7abc7b69cb249fe27d2014a821e437 to your computer and use it in GitHub Desktop.
Save Octachron/6a7abc7b69cb249fe27d2014a821e437 to your computer and use it in GitHub Desktop.
Simple Input monad
type 'a t =
| Constant of 'a
(** [Constant x] is a normal value *)
| Input of (int -> 'a t)
(** [Input x] is a value which is blocked on an missing (int) user input *)
let pure x = Constant x
(** [int: int t] is the core extension of ['a t] compared to normal values ['a]:
it is a concrete representation of the action "reading an integer on stdin"
*)
let int = Input pure
(** How to chain a value that might require a read with a function that might
perform read *)
let rec bind f x = match x with
| Constant x ->
(** if the value doesn't require any read, we can use the function directly *)
f x
| Input i ->
(** If the value was already waiting for a read, we can only start [f] after the read
has been done: *)
Input (fun n ->
let x_after_one_read = i n in
(** we have performed the first pending read, we retry to compute f *)
bind f x_after_one_read
)
(** Perform one pending read if any *)
let run_once = function
| Constant _ as x -> x
| Input i -> Scanf.scanf "%d\n" i
(** The EDSL interpreter [run x] performs as many read as needed
to obtain a [Constant value], and then returns [value].
*)
let rec run = function
| Constant x -> x
| Input _ as i -> run (run_once i)
let (let*) x f = bind f x
let multiply_three_number =
let* x = int in
let* y = int in
let* z = int in
pure (x * y * z)
let () =
let mx = run multiply_three_number in
Format.printf "Result:%d@." mx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment