Created
November 18, 2021 17:33
-
-
Save luther9/8ed291c9c12a44388e341e7f63f5b3cc to your computer and use it in GitHub Desktop.
Revisions
-
luther9 created this gist
Nov 18, 2021 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,104 @@ #!/usr/bin/env lua local IO IO = { -- Class method. Create an IO that does nothing and returns x. unit = function(x) return IO(function() return x end) end, -- Class method. Return a function which is like f, except it returns an IO -- that represents f's action. wrap = function(f) return function(...) local args <const> = table.pack(...) return IO(function() return f(table.unpack(args, 1, args.n)) end) end end, bind = function(self, f) return IO(function() return f(self())() end) end, -- Bind two IOs together, discarding a's value. Equivalent to -- a:bind(const(b)). seq = function(a, b) return IO( function() a() return b() end) end, rep = function(self, runs, f, init) local function loop(runs, x) if runs < 1 then return x end return loop(runs - 1, f(x, self())) end return IO(function() return loop(runs, init) end) end, } setmetatable( IO, { -- Construct a primitive IO with an impure function that takes no arguments. -- Equivalant to Haskell's 'ccall'. __call = function(cls, effect) local o <const> = {} setmetatable(o, {__index = cls, __call = effect}) return o end, }) local random <const> = IO.wrap(math.random) local print <const> = IO.wrap(print) -- Based on https://www.youtube.com/watch?v=r6qg4NaUvfI&t=90s local function simulateMonty(doorCount, swap) return random(doorCount) :bind( function(carDoor) return IO.unit(not not swap ~= (carDoor == 1)) end) end -- Not a side-effect. It starts the program off at a known state. math.randomseed(0) local runs <const> = 1000000 local doors <const> = 26 local function simulate(swap) return simulateMonty(doors, swap):rep( runs, function(wins, win) if win then return wins + 1 end return wins end, 0) end -- Main program simulate(false) :bind( function(wins) return print( ('We won %d times out of %d without swapping.'):format(wins, runs)) end) :seq( simulate(true) :bind( function(wins) return print( ('We won %d times out of %d while swapping.'):format(wins, runs)) end)) ()