Skip to content

Instantly share code, notes, and snippets.

@archseer
Last active August 29, 2015 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save archseer/abd6ead4e7482425d428 to your computer and use it in GitHub Desktop.
Save archseer/abd6ead4e7482425d428 to your computer and use it in GitHub Desktop.
# Adapted from http://phuu.net/2014/08/31/csp-and-transducers.html
compose = -> (f, g) {
return -> x { f.(g.(x)) }
}
fn = compose.(-> x {x + 1}, -> x {x * 3})
fn.(1)
# Map function derivation
# 1
[1,2,3,4].map do |input|
input + 1
end # => [2,3,4,5]
# 2
concat = -> (a, b) { a.concat([b]) }
[1,2,3,4].reduce([]) do |result, input|
concat.(result, input + 1)
end # => [2,3,4,5]
# 3
inc = -> x { x + 1 }
map = -> (transform, collection) {
return collection.reduce([]) do |result, input|
concat.(result, transform.(input))
end
}
map.(inc, [1,2,3,4])
# Algorithmic transformations
## Basic filter
[1,2,3,4].select do |input| #.filter
input > 2
end # => [3,4]
## Filter with reduce
[1,2,3,4].reduce([]) do |result, input|
input > 2 ?
concat.(result, input) :
result
end # => [3,4]
## Transform (called the predicate)
greaterThanTwo = -> x {
return x > 2
}
## And finally, filter as function
filter = -> (predicate, collection) {
return collection.reduce([]) do |result, input|
predicate.(input) ?
concat.(result, input) :
result
end
}
## Run it!
filter.(greaterThanTwo, [1,2,3,4]) # => [3,4]
## Compose!
incrementAndFilter = compose.(
-> x { filter.(greaterThanTwo, x)},
-> x { map.(inc, x)},
)
incrementAndFilter.([1,2,3,4]) # => [3,4,5]
# Reducing functions
mapper = -> (transform) {
return -> (result, input) {
return concat.(result, transform.(input))
}
}
filterer = -> (predicate) {
return -> (result, input) {
predicate.(input) ?
concat.(result, input) :
result
}
}
[1,2,3,4].reduce([], &mapper.(inc)) # => [2,3,4,5]
[1,2,3,4].reduce([], &filterer.(greaterThanTwo)) # => [3,4]
## Identity function
identity = -> (x) { x }
[1,2,3,4].reduce([], &mapper.(identity)) # => [1,2,3,4]
## Filter with mapper
lessThanThree = -> x {
return x < 3
}
mapper = -> (transform) {
return -> (result, input) {
return concat.(result, transform.(input))
}
}
filterer = -> (predicate) {
return -> (result, input) {
predicate.(input) ?
mapper.(identity).(result, input) :
result
}
}
[1,2,3,4].reduce([], &filterer.(lessThanThree)) # => [1,2]
## Getting to transformations
mapping = -> (transform) {
return -> (reduce) {
return -> (result, input) {
return reduce.(result, transform.(input))
}
}
}
filtering = -> (predicate) {
return -> (reduce) {
return -> (result, input) {
predicate.(input) ?
reduce.(result, input) :
result
}
}
}
filterLessThanThreeAndIncrement = compose.(
filtering.(lessThanThree),
mapping.(inc),
)
[1,2,3,4].reduce([], &filterLessThanThreeAndIncrement.(concat)) # => [2,3]
### Changing the reducer
[1,2,3,4].reduce({}, &filterLessThanThreeAndIncrement.(-> (result, input) {
result[input] = true
return result
})) # => { 2: true, 3: true }
### Complex data
posts = [
{ author: 'Agatha', text: 'just setting up my pstr' },
{ author: 'Bert', text: 'Ed Balls' },
{ author: 'Agatha', text: '@Bert fancy a thumb war?' },
{ author: 'Charles', text: '#subtweet' },
{ author: 'Bert', text: 'Ed Balls' },
{ author: 'Agatha', text: '@Bert m(' }
]
graph = -> (result, input) {
(result[input[:from]] ||= []) << input[:to]
return result
}
extractMentions = compose.(
# Find mentions
filtering.(-> (post) {
return post[:text].match(/^@/)
}),
# Build object with {from, to} keys
mapping.(-> (post) {
return {
from: post[:author],
to: post[:text].split(' ').shift.sub(/^@/, '')
}
})
)
puts posts.reduce({}, &extractMentions.(graph))
# => { Agatha: ['Bert', 'Charles'],
# Bert: ['Agatha'],
# Charles: ['Bert'] }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment