# # 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)); }