summaryrefslogtreecommitdiff
path: root/nix-turing/io.nix
blob: 7f904d67ffc7a88709ca531f375fac252caecc87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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 <nixpkgs> {};

  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 <nixpkgs> {};
          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));
}