Skip to content

Instantly share code, notes, and snippets.

@havenwood
Forked from dminuoso/van_laarhoven_lens.rb
Created November 6, 2017 23:42

Revisions

  1. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 18 additions and 0 deletions.
    18 changes: 18 additions & 0 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -83,6 +83,12 @@ def fmap(*args)
    end
    end

    def const(*args)
    -> (val) {
    -> (_) { val }
    }.curry[*args]
    end

    module L
    class << self
    def ens(*args)
    @@ -106,6 +112,12 @@ def view(*args)
    lens.(Const.make).(obj).value
    }.curry[*args]
    end

    def set(*args)
    -> (lens, val, obj) {
    over(lens, const(val), obj)
    }.curry[*args]
    end
    end
    end

    @@ -158,6 +170,12 @@ def self.lens_path(*args)
    profile
    )

    puts L.set(
    ability_l,
    'composing functions',
    profile
    )

    puts L.over(
    ability_l,
    upcase,
  2. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 11 additions and 4 deletions.
    15 changes: 11 additions & 4 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -103,7 +103,7 @@ def over(*args)

    def view(*args)
    -> (lens, obj) {
    lens.(Const.make, obj).value
    lens.(Const.make).(obj).value
    }.curry[*args]
    end
    end
    @@ -149,16 +149,23 @@ def self.lens_path(*args)
    }
    }

    friend_ability_l = Hash.lens_path([:friend, :details, :ability])
    friend_l = Hash.lens_path([:friend])
    ability_l = Hash.lens_path([:details, :ability])
    upcase = -> (e) { e.upcase }

    puts L.view(
    friend_ability_l,
    friend_l * ability_l,
    profile
    )

    puts L.over(
    friend_ability_l,
    ability_l,
    upcase,
    profile
    )

    puts L.over(
    friend_l * ability_l,
    upcase,
    profile
    )
  3. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -149,12 +149,11 @@ def self.lens_path(*args)
    }
    }

    friend_l = Hash.lens_path([:friend])
    ability_l = Hash.lens_path([:details, :ability])
    friend_ability_l = Hash.lens_path([:friend, :details, :ability])
    upcase = -> (e) { e.upcase }

    puts L.view(
    friend_l * ability_l,
    friend_ability_l,
    profile
    )

  4. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,7 @@ def deep_dup

    class Proc
    def *(other)
    -> (*args) { self[other[args]] }
    -> (*args) { self[other[*args]] }
    end
    end

    @@ -138,6 +138,9 @@ def self.lens_path(*args)

    profile = {
    username: 'dminuoso',
    details: {
    ability: 'writing functions',
    },
    friend: {
    name: 'baweaver',
    details: {
    @@ -146,11 +149,12 @@ def self.lens_path(*args)
    }
    }

    friend_ability_l = Hash.lens_path([:friend, :details, :ability])
    friend_l = Hash.lens_path([:friend])
    ability_l = Hash.lens_path([:details, :ability])
    upcase = -> (e) { e.upcase }

    puts L.view(
    friend_ability_l,
    friend_l * ability_l,
    profile
    )

  5. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -70,7 +70,7 @@ def self.lens_index(*args)

    def self.update(*args)
    -> (n, v, array) {
    array[n] = v
    array.deep_dup.tap { |a| a[n] = v }
    }.curry[*args]
    end
    end
  6. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 7 additions and 5 deletions.
    12 changes: 7 additions & 5 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -50,9 +50,10 @@ def deep_dup
    map(&:deep_dup)
    end

    def fmap(func = nil, &blk)
    f = func || blk
    map(&f)
    def fmap(*args)
    -> (fun, e) {
    e.map(&fun)
    }.curry[*args]
    end

    def self.nth(*args)
    @@ -76,7 +77,9 @@ def self.update(*args)

    module Kernel
    def fmap(*args)
    -> (fn, e) { e.class.instance_method(:fmap).bind(e).call(fn) }.curry[*args]
    -> (fn, e) {
    e.class.instance_method(:fmap).bind(e).call(fn)
    }.curry[*args]
    end
    end

    @@ -133,7 +136,6 @@ def self.lens_path(*args)
    end
    end


    profile = {
    username: 'dminuoso',
    friend: {
  7. @dminuoso dminuoso revised this gist Nov 6, 2017. 1 changed file with 9 additions and 9 deletions.
    18 changes: 9 additions & 9 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ def deep_dup
    hash[key.deep_dup] = value.deep_dup
    end
    end
    hash
    hash
    end
    end

    @@ -135,13 +135,13 @@ def self.lens_path(*args)


    profile = {
    username: 'dminuoso',
    friend: {
    name: 'baweaver',
    details: {
    ability: 'puns',
    }
    }
    username: 'dminuoso',
    friend: {
    name: 'baweaver',
    details: {
    ability: 'puns',
    }
    }
    }

    friend_ability_l = Hash.lens_path([:friend, :details, :ability])
    @@ -153,7 +153,7 @@ def self.lens_path(*args)
    )

    puts L.over(
    friend_ability_l,
    friend_ability_l,
    upcase,
    profile
    )
  8. @dminuoso dminuoso created this gist Nov 6, 2017.
    159 changes: 159 additions & 0 deletions van_laarhoven_lens.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,159 @@
    # Identity functor that does not give any additional structure
    Identity = Struct.new(:value) do
    def fmap(func = nil, &blk)
    f = func || blk;
    Identity.new(f.call(self.value))
    end
    end

    # Const Functor that preserves its content
    Const = Struct.new(:value) do
    def fmap(f = nil, o = nil)
    self
    end

    # A curried constructor for sanity.
    def self.make(*args)
    -> (o) { new(o) }.curry[*args]
    end
    end

    class Object
    def deep_dup
    dup
    end
    end

    class Hash
    def deep_dup
    hash = dup
    each_pair do |key, value|
    if key.frozen? && ::String === key
    hash[key] = value.deep_dup
    else
    hash.delete(key)
    hash[key.deep_dup] = value.deep_dup
    end
    end
    hash
    end
    end

    class Proc
    def *(other)
    -> (*args) { self[other[args]] }
    end
    end

    class Array
    def deep_dup
    map(&:deep_dup)
    end

    def fmap(func = nil, &blk)
    f = func || blk
    map(&f)
    end

    def self.nth(*args)
    -> (n) {
    -> (o) { o[n] }
    }.curry[*args]
    end

    def self.lens_index(*args)
    -> (n) {
    L.ens(nth(n), update(n))
    }.curry[*args]
    end

    def self.update(*args)
    -> (n, v, array) {
    array[n] = v
    }.curry[*args]
    end
    end

    module Kernel
    def fmap(*args)
    -> (fn, e) { e.class.instance_method(:fmap).bind(e).call(fn) }.curry[*args]
    end
    end

    module L
    class << self
    def ens(*args)
    -> (g, s, w, t) {
    fmap(-> (f) {
    s.(f, t)
    }, w.(g.(t)))
    }.curry[*args]
    end

    def over(*args)
    -> (lens, fun, obj) {
    lens.(-> (y) {
    Identity.new(fun.(y))
    }).(obj).value
    }.curry[*args]
    end

    def view(*args)
    -> (lens, obj) {
    lens.(Const.make, obj).value
    }.curry[*args]
    end
    end
    end

    class Hash
    def self.getter(*args)
    -> (paths, obj) {
    obj.dig(*paths)
    }.curry[*args]
    end

    def self.setter(*args)
    -> (paths, val, obj) {
    obj.deep_dup.tap do |o|
    *dir, final = paths
    if dir.empty?
    o.store(final, val)
    else
    o.dig(*dir).store(final, val)
    end
    end
    }.curry[*args]
    end

    def self.lens_path(*args)
    -> (paths) {
    L.ens(getter(paths), setter(paths))
    }.curry[*args]
    end
    end


    profile = {
    username: 'dminuoso',
    friend: {
    name: 'baweaver',
    details: {
    ability: 'puns',
    }
    }
    }

    friend_ability_l = Hash.lens_path([:friend, :details, :ability])
    upcase = -> (e) { e.upcase }

    puts L.view(
    friend_ability_l,
    profile
    )

    puts L.over(
    friend_ability_l,
    upcase,
    profile
    )