Skip to content

Instantly share code, notes, and snippets.

@dminuoso
Created November 6, 2017 17:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dminuoso/a4d1f3f86fcada1ffdde9fed81fa7e12 to your computer and use it in GitHub Desktop.
Save dminuoso/a4d1f3f86fcada1ffdde9fed81fa7e12 to your computer and use it in GitHub Desktop.
Identity = Struct.new(:value) do
def fmap(*args)
-> (func) {
Identity.new(func.call(self.value))
}.curry[*args]
end
end
Const = Struct.new(:value) do
def fmap(*args)
-> (func) { self }.curry[*args]
end
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(*args)
-> (fun, e) {
e.map(&fun)
}.curry[*args]
end
def self.nth(*args)
-> (n, o) {
o[n]
}.curry[*args]
end
def self.lens_at(*args)
-> (n) {
L.ens(nth(n), setter(n))
}.curry[*args]
end
def self.setter(*args)
-> (n, val, array) {
array.deep_dup.tap { |a| a[n] = val }
}.curry[*args]
end
end
module Kernel
def fmap(*args)
-> (fn, e) {
e.class.instance_method(:fmap).bind(e).call(fn)
}.curry[*args]
end
end
def const(*args)
-> (val, _) {
val
}.curry[*args]
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
def set(*args)
-> (lens, val, obj) {
over(lens, const(val), obj)
}.curry[*args]
end
end
end
class Hash
def self.path(*args)
-> (paths, hash) {
hash.dig(*paths)
}.curry[*args]
end
def self.setter(*args)
-> (paths, val, hash) {
hash.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(path(paths), setter(paths))
}.curry[*args]
end
end
profile = {
username: 'dminuoso',
hobbies: ['fixing ruby', 'being weird'],
details: {
ability: 'writing functions',
},
friends: [
{
name: 'baweaver',
details: {
ability: 'puns',
}
}
],
enemies: [
{
name: 'Papierkorb',
details: {
ability: 'being mean :(',
}
}
]
}
flip = -> (a) { -> (f,s) { a[s,f] }.curry }
concat = -> (a, b) { a + b }
friend_l = Hash.lens_path([:friends])
ability_l = Hash.lens_path([:details, :ability])
hobbies_l = Hash.lens_path([:hobbies])
enemies_l = Hash.lens_path([:enemies])
first_l = Array.lens_at(0)
upcase = -> (e) { e.upcase }
scream = flip.(concat).('!!!') * upcase
puts L.over(
enemies_l * first_l * ability_l,
scream,
profile
)
<<CMT
puts L.view(
hobbies_l * first_l,
profile
)
puts L.view(
friend_l * first_l * ability_l,
profile
)
puts L.set(
ability_l,
'composing functions',
profile
)
puts L.over(
ability_l,
upcase,
profile
)
puts L.over(
friend_l * first_l * ability_l,
upcase,
profile
)
CMT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment