create = (db, document) ->
  deferred = new $.Deferred()

  $.getJSON("/_uuids").success (resp) ->
    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    $.putJSON(docURL, document).success ->

      $.getJSON(docURL).success (updatedDoc) ->
        deferred.resolve updatedDoc

  deferred
    
create = (db, document) ->
  deferred = new $.Deferred()

  $.getJSON("/_uuids").success (resp) ->
    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    $.putJSON(docURL, document).success ->

      $.getJSON(docURL).success (updatedDoc) ->
        deferred.resolve updatedDoc

  deferred
    
function create(db, document) {
    var deferred = new $.Deferred()

    $.getJSON("/_uuids").success(function(resp) {
        var id = resp.uuids[0];
        var docURL = "/"+ db +"/"+ id;

        $.putJSON(docURL, document).success(function() {

            $.getJSON(docURL).success(function(updatedDoc) {
                deferred.resolve(updatedDoc);
            });
        });
    });

    return deferred;
}
    
asyncFunction = (arg) ->
  deferred = new $.Deferred()

  doStuff arg, (result) ->
    deferred.resolve result

  deferred

asyncFunction("foo").done (result) ->
  print result
    
asyncFunction = (arg, callback) ->
  doStuff arg, (result) ->
    callback(result)

asyncFunction "foo", (result) ->
  print result
    
create = (db, document) ->
  deferred = new $.Deferred()

  $.getJSON("/_uuids").success((resp) ->
    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    $.putJSON(docURL, document).success( ->

      $.getJSON(docURL).success((updatedDoc) ->
        deferred.resolve updatedDoc
      ).error (xhr, textStatus) ->
        deferred.reject xhr, textStatus

    ).error (xhr, textStatus) ->
      deferred.reject xhr, textStatus

  ).error (xhr, textStatus) ->
    deferred.reject xhr, textStatus

  deferred
    
create = (db, document) ->
  do
    resp <- $.getJSON "/_uuids"

    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    _ <- $.putJSON docURL, document

    updatedDoc <- $getJSON docURL

  yield
    updatedDoc
    
create = (db, document) ->
  $.getJSON("/_uuids").flatMap (resp) ->
    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    $.putJSON(docURL, document).flatMap (_) ->

      $.getJSON(docURL).map (updatedDoc) ->
        updatedDoc
    
$.Deferred.prototype.flatten = ->
  deferred = new $.Deferred()

  this.done (deferredPrime) ->
    deferredPrime.done (values...) ->
      deferred.resolve values...

    deferredPrime.fail (msgs...) ->
      deferred.reject msgs...

  this.fail (msgs...) ->
    deferred.reject msgs...

  deferred

$.Deferred.prototype.map = (f) ->
  deferred = new $.Deferred()

  this.done (values...) ->
    deferred.resolve (f values...)

  this.fail (msgs...) ->
    deferred.reject msgs...

  deferred

$.Deferred.prototype.flatMap = (f) ->
  (this.map f).flatten
    
create = (db, document) ->
  $.getJSON("/_uuids").flatMap (resp) ->
    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    $.putJSON(docURL, document).flatMap ->

      $.getJSON(docURL).map (updatedDoc) ->
        updatedDoc
    
create = (db, document) ->
  deferred = new $.Deferred()

  $.getJSON("/_uuids").success((resp) ->
    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    $.putJSON(docURL, document).success( ->

      $.getJSON(docURL).success((updatedDoc) ->
        deferred.resolve updatedDoc
      ).error (xhr, textStatus) ->
        deferred.reject xhr, textStatus

    ).error (xhr, textStatus) ->
      deferred.reject xhr, textStatus

  ).error (xhr, textStatus) ->
    deferred.reject xhr, textStatus

  deferred
    
gameOfLife = (board) ->
  do
    row  <- board
    cell <- row
  yield
    { x, y, isAlive } = cell

    stillAlive = switch neighborCount(x, y)
      when 2 then isAlive
      when 3 then true
      else false

    { x: x, y: y, isAlive: stillAlive }
    
flatMap = (obj, f) ->
  if $.isArray obj
    mapped = obj.map f
    mapped.reduce ((out, e) -> out.concat e), []
  else
    obj.flatMap f
    
class Show a where
    show :: a -> String

instance Show String where
    show s = s

show "foo" == "foo"

instance (Show a) => Show [a] where
    show l = "["++ (intercalate "," $ map show l) ++"]"

show [1, 2, 3, 4] == "[1, 2, 3, 4]"
    
(defprotocol Show
  "Produce a string representation of a given value"
  (show [a] "returns a string representation of a"))

(deftype Foo [])
(deftype Bar [prop])

(extend Foo Show
  {:show (fn [x] "foo")})

(extend Bar Show
  {:show (fn [x] (let [s show (. x prop)]
           (str "bar[" s "]")))})

(let [foo (new Foo)]
  (= (show foo) "foo"))

(let [foo (new Foo)
      bar (new Bar foo)]
  (= (show bar) "bar[foo]"))
    
Show = Protocol
  show: Protocol.required

extend String, Show
  show: (s) -> s

extend Array, Show
  show: (a) -> "["+ (a.map (e) -> show e).join(", ") +"]"

show "foo" == "foo"

show ["foo", "bar"] == "[foo, bar]"
    
Functor = new Protocol
  map: Protocol.required

Monad = new Protocol
  flatMap: (m, f) -> Monad.flatten (Functor.map m, f)
  flatten: (m)    -> Monad.flatMap m, (v) -> v
  compose: (m, k) -> Monad.flatMap m, (_) -> k
    
create = (db, document) ->
  do
    resp <- $.getJSON "/_uuids"

    id = resp.uuids[0]
    docURL = "/#{db}/#{id}"

    _ <- $.putJSON docURL, document

    updatedDoc <- $getJSON docURL

  yield
    updatedDoc
    
Protocol = (signatures) ->
  @impls = {}

  findImpl = (object) ->
    constructor = object.constructor
    impl = @impls[constructor]
    if impl
      impl
    else if (constructor and
             constructor.prototype and
             constructor.prototype !== Object
      getImplementation constructor.prototype

  Object.keys(signatures).forEach (name) =>
    @[name] = (firstArg, args...) ->
      impl = findImpl firstArg
      func = impl[name]

      func firstArg, args...
    
Protocol = (signatures) ->
  @impls = {}

  findImpl = (object) ->
    @impls["__protocol_crumb__"]

  Object.keys(signatures).forEach (name) =>
    @[name] = (firstArg, args...) ->
      impl = findImpl firstArg
      func = impl[name]

      func firstArg, args...

Protocol.counter = 0

extend = (type, protocol, impl) ->
  type.prototype["__protocol_crumb__"] = Protocol.counter
  protocol.impls[Protocol.counter] = impl
  Protocol.counter += 1
    
_ = undefined
signature = Protocol.signature

Functor = new Protocol (a) ->
  map: signature _, a

extend Array, Functor,
  map: (f, array) -> array.map f
    

Links