From 3d498c134a9c0ab61c86a233edd0b2eb76ef44eb Mon Sep 17 00:00:00 2001 From: stuebinm Date: Tue, 20 Jul 2021 20:43:16 +0200 Subject: playing around with IO in Nix --- nix-turing/io.nix | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 nix-turing/io.nix (limited to 'nix-turing/io.nix') diff --git a/nix-turing/io.nix b/nix-turing/io.nix new file mode 100644 index 0000000..7f904d6 --- /dev/null +++ b/nix-turing/io.nix @@ -0,0 +1,147 @@ +# +# General purpose programming Nix: Plan of attack +# =============================================== +# +# 1. define some nice attrset that all these functions +# pass to each other implicitely +# 2. minimise unnecessary build output +# 3. a monadic do notation taking a list of monad operations? +# (how to deal with variables?) +# 4. implement tic tac toe +# +# TODO +# - nicer syntax +# - put this into a library +# - make the seed configurable via cli +# - tic tac toe +# let +{ s, ... }: rec { + pkgs = import {}; + + seed = toString s; + eval = code: import (pkgs.writeText "code" code); + + pause = idx: prompt: pkgs.stdenv.mkDerivation { + name = "sleep-${seed}"; + src = pkgs.hello; + phases = [ "buildPhase" ]; + buildPhase = '' + echo + echo + echo ${pkgs.lib.escapeShellArg prompt} + sleep 2 + echo waiting 3 ... + sleep 2 + echo waiting 2 ... + sleep 2 + echo waiting 1 ... + mkdir -p $out + ''; + }; + + pause_and = { prev, idx, inputCounter, ... }: prompt: code: { + prev = pkgs.stdenv.mkDerivation { + name = "pause_and-${toString idx}"; + buildInputs = [ ( pause idx prompt ) ]; + phases = [ "buildPhase" ]; + src = pkgs.writeText "code" code; + buildPhase = '' + echo ${if prev != null then prev.outPath else ""} + # ${seed} + cp $src $out + ''; + }; + idx = idx; + inherit inputCounter; + }; + + read_input = prompt: realWorld: + let nextWorld = pause_and + realWorld + '' + ${prompt} + please enter your input in file /tmp/input-${toString realWorld.inputCounter} + '' + '' + with import {}; + lib.readFile + "/tmp/input-${toString realWorld.inputCounter}" + # ${seed} + # ${if realWorld.prev != null + then realWorld.prev.outPath + else ""} + ''; + in + { + prev = nextWorld.prev; + value = realWorld.value // { + input = import nextWorld.prev.outPath; + }; + inputCounter = nextWorld.inputCounter + 1; + idx = nextWorld.idx + 1; + }; + + print = msg: realWorld: { + prev = pkgs.stdenv.mkDerivation { + name = "log-derivation"; + phases = [ "print" ]; + print = '' + echo ${pkgs.lib.escapeShellArg msg} + echo ${pkgs.lib.escapeShellArg msg} > $out + # ${toString realWorld.idx} + # ${seed} + # ${if realWorld.prev != null + then realWorld.prev.outPath + else ""} + ''; + }; + idx = realWorld.idx + 1; + inherit (realWorld) inputCounter value; + }; + + log = msg: + print "==============LOG===============\n${msg}"; + + initialWorld = { + prev = null; + idx = 0; + inputCounter = 0; + value = {}; + }; + + call = realWorld: + realWorld.prev; + + assign = name: value: realWorld: + realWorld // {value = realWorld.value // {${name} = value;};}; + + # the IO monad + bind = monadic: operation: + monadic // ((operation monadic.value) monadic); + + bindMonadic = operation: monadic: + bind monadic operation; + + unit = realWorld: realWorld; + + # basic do notation + do = monadic: operations: + pkgs.lib.foldl bind monadic operations; + + # flipped version of do for usage in bound + doMonadic = operations: monadic: + do monadic operations; + + ifThenElse = cond: ifTrue: ifFalse: + (v: if cond v + then ifTrue v + else ifFalse v); + + while = cond: body: + (ifThenElse cond + (v: doMonadic [ + body + (while cond body) + ]) + (v: unit)); +} -- cgit v1.2.3