Skip to content

Instantly share code, notes, and snippets.

@weapp
Last active February 7, 2022 17:21
Show Gist options
  • Save weapp/3548707977403bb12262 to your computer and use it in GitHub Desktop.
Save weapp/3548707977403bb12262 to your computer and use it in GitHub Desktop.
Experiment about functional programing in different languages

Definitions:

  • callable: something that can be called with params; like a function, method, procedure, macro...
  • Point:: 2d tuple/list/array or object/struct with coordinates (x, y) as attributes/fields
  • Region: a callable that receive a point and return true if is inside of a a region, and false if is out.
  • Distance : a float

Problem:

  • We have a two tanks (in a two positions), and we want to know if we can shot to another positions without danger.
  • The tanks have a secure region defined by a circle
  • The tanks have a maximun shot distance.

Requisites of solution:

  • Implement a callable named circle that receive a float that represent the radius and return a Region of a circle centered on the origin of coordinates with this radius.

  • Implement operations shift, difference, circle, and difference for Regions.

  • Implement a callable named target based on the above operations that return the Region wich is the response of the problem.

  • target will receive 3 params:

    • Distance max_distance: max range of shot.
    • Distance min_distance: radius of secure region.
    • Position friend: coordinates of the friend's tank.
circle = (radius) -> (p) -> (p.x ** 2 + p.y ** 2) ** (1/2) < radius
offset = (reg, pos) -> (p) -> reg x: p.x - pos.x, y: p.y - pos.y
inverse = (reg) -> (p) -> not reg(p)
intersection = (reg1, reg2) -> (p) -> reg1(p) and reg2(p)
difference = (reg1, reg2) -> intersection reg1, inverse(reg2)
target = (max_distance, min_distance, friend) ->
donnut_region = difference circle(max_distance), circle(min_distance)
friend_region = offset circle(min_distance), friend
difference donnut_region, friend_region
region = target(3, 1, {x: 2, y: 2})
console.log region(x: 1, y: 1) # => true
console.log region(x: 2, y: 2) # => false
console.log region(x: 2, y: -2) # => true
var circle = radius => p => Math.sqrt(p.x * p.x + p.y * p.y) < radius
var shift = (reg, pos) => p => reg({x: p.x - pos.x, y: p.y - pos.y})
var inverse = reg => p => !reg(p)
var intersection = (reg1, reg2) => p => reg1(p) && reg2(p)
var difference = (reg1, reg2) => intersection(reg1, inverse(reg2))
var target = (max_distance, min_distance, friend) => {
donnut_region = difference(circle(max_distance), circle(min_distance))
friend_region = shift(circle(min_distance), friend)
return difference(donnut_region, friend_region)
}
region = target(3, 1, {x: 2, y: 2})
console.log(region({x: 1, y: 1}))
import :math, only: [sqrt: 1, pow: 2]
defmodule Regions do
defmodule Point, do: defstruct x: 0, y: 0
def point(x, y) do
%Point{x: x, y: y}
end
def circle(distance) do
fn point -> sqrt( pow(point.x, 2) + pow(point.y, 2) ) < distance end
end
def shift(region, position) do
fn point -> region.(point(point.x - position.x, point.y - position.y)) end
end
def inverse(region) do
fn point -> !region.(point) end
end
def intersection(region1, region2) do
fn point -> region1.(point) && region2.(point) end
end
def difference(region1, region2) do
intersection(region1, inverse(region2))
end
def target(max_distance, min_distance, friend) do
donnut_region = difference(circle(max_distance), circle(min_distance))
friend_region = shift(circle(min_distance), friend)
difference(donnut_region, friend_region)
end
end
region = Regions.target(3, 1, Regions.point(2, 2))
IO.inspect region.(Regions.point(1, 1)) # => true
IO.inspect region.(Regions.point(2, 2)) # => false
IO.inspect region.(Regions.point(2, -2)) # => true
package main
import (
"fmt"
"math"
)
type Point struct{ X, Y float64 }
type Distance float64
type Region func(Point) bool
func circle(radius Distance) Region {
return func(p Point) bool { return math.Sqrt(p.X*p.X+p.Y*p.Y) <= float64(radius) }
}
func (reg Region) shift(pos Point) Region {
return func(p Point) bool { return reg(Point{p.X - pos.X, p.Y - pos.Y}) }
}
func (reg Region) intersection(other Region) Region {
return func(p Point) bool { return reg(p) && other(p) }
}
func (reg Region) invert() Region {
return func(p Point) bool { return !reg(p) }
}
func (reg Region) difference(other Region) Region {
return reg.intersection(other.invert())
}
func target(max_distance Distance, min_distance Distance, friend Point) Region {
donnut_region := circle(max_distance).difference(circle(min_distance))
friend_region := circle(min_distance).shift(friend)
return donnut_region.difference(friend_region)
}
func main() {
region := target(3, 1, Point{X: 2.0, Y: 2.0})
fmt.Printf("%v\n", region(Point{X: 1.0, Y: 1.0})) // => true
fmt.Printf("%v\n", region(Point{X: 2.0, Y: 2.0})) // => false
fmt.Printf("%v\n", region(Point{X: 2.0, Y: -2.0})) // => true
}
// $ go run regions.go
type Point = (Double, Double)
type Region = Point -> Bool
type Distance = Double
circle :: Distance -> Region
circle r (x, y) = sqrt(x^2 + y^2) < r
shift :: Region -> Point -> Region
shift region (x, y) (x', y') = region (x - x', y - y')
inverse :: Region -> Region
inverse region (x, y) = not (region (x, y))
intersection :: Region -> Region -> Region
intersection region1 region2 point = (region1 point) && (region2 point)
difference :: Region -> Region -> Region
difference region1 region2 = (intersection region1 (inverse region2))
target :: Distance -> Distance -> Point -> Region
target max_distance min_distance friend =
let donnut = difference (circle max_distance) (circle min_distance)
friendly = shift (circle min_distance) friend
in difference donnut friendly
-- $ ghci
-- :l regions
-- > target 3 1 (2, 2) (1, 1)
-- True
-- > target 3 1 (2, 2) (2, 2)
-- False
-- > target 3 1 (2, 2) (2, -2)
-- True
var circle = function(distance){
return function(point){ return (Math.sqrt(Math.pow(point.x, 2.0) + Math.pow(point.y, 2.0))) < distance; };
}
var shift = function(region, position){
return function(point){ return region({x: point.x - position.x, y: point.y - position.y}); };
}
var inverse = function(region){
return function(point){ return !region(point); };
}
var intersection = function(region1, region2){
return function(point){ return region1(point) && region2(point); };
}
var difference = function(region1, region2){
return intersection(region1, inverse(region2));
}
var target = function(max_distance, min_distance, friend){
donnut_region = difference(circle(max_distance), circle(min_distance))
friend_region = shift(circle(min_distance), friend)
return difference(donnut_region, friend_region)
}
region = target(3, 1, {x: 2, y: 2})
console.log(region({x: 1, y: 1}))
(defun circle (r) (lambda (p)
(< (sqrt (+ (* (getf p 'x) (getf p 'x)) (* (getf p 'y) (getf p 'y)))) r)))
(defun shift (reg pos) (lambda (p)
(funcall reg (list 'x (- (getf p 'x) (getf pos 'x)) 'y (- (getf p 'y) (getf pos 'y))))))
(defun inverse (reg) (lambda (p)
(not (funcall reg p))))
(defun reg_intersection (reg1 reg2) (lambda (p)
(and (funcall reg1 p) (funcall reg2 p))))
(defun difference (reg1 reg2)
(reg_intersection reg1 (inverse reg2)))
(defun target (max_distance min_distance friend)
(let ((donnut (difference (circle max_distance) (circle min_distance)))
(friendly (shift (circle min_distance) friend)))
(difference donnut friendly)))
(let ((region (target 3 1 (list 'x 2 'y 2) )))
(prin1 (funcall region (list 'x 1 'y 1))) ; => T
(print (funcall region (list 'x 2 'y 2))) ; => NIL
(print (funcall region (list 'x 2 'y -2))) ; => T
)
circle = function(distance)
return function(point)
return (math.sqrt(math.pow(point.x, 2.0) + math.pow(point.y, 2.0))) < distance
end
end
shift = function(region, position)
return function(point)
return region({x=point.x - position.x, y=point.y - position.y})
end
end
inverse = function(region)
return function(point)
return not region(point)
end
end
intersection = function(region1, region2)
return function(point)
return region1(point) and region2(point)
end
end
difference = function(region1, region2)
return intersection(region1, inverse(region2));
end
target = function(max_distance, min_distance, friend)
donnut_region = difference(circle(max_distance), circle(min_distance))
friend_region = shift(circle(min_distance), friend)
return difference(donnut_region, friend_region)
end
region = target(3, 1, {x=2, y=2})
print(region({x=1, y=1}))
print(region({x=2, y=2}))
print(region({x=2, y=-2}))
import :math, only: [sqrt: 1, pow: 2]
defmodule Regions do
def circle(distance), do: &(sqrt( pow(&1[:x], 2) + pow(&1[:y], 2) ) < distance)
def shift(reg, pos), do: &(reg.([x: &1[:x] - pos[:x], y: &1[:y] - pos[:y]]))
def inverse(reg), do: &(!reg.(&1))
def region1 &&& region2, do: &(region1.(&1) && region2.(&1))
def diff(region1, region2), do: region1 &&& inverse region2
def target(max, min, friend), do: donnut(max, min) |> diff( friendly(min, friend) )
defp donnut(max, min), do: circle(max) |> diff( circle(min) )
defp friendly(min, friend), do: circle(min) |> shift(friend)
end
region = Regions.target(3, 1, [x: 2, y: 2])
IO.inspect region.([x: 1, y: 1]) # => true
IO.inspect region.([x: 2, y: 2]) # => false
IO.inspect region.([x: 2, y: -2]) # => true
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
def circle(distance):
return lambda point: (point.x ** 2. + point.y ** 2.) ** (1/2.) < distance
def shift(region, position):
return lambda point: region(Point(x=point.x-position.x, y=point.y-position.y))
def inverse(region):
return lambda point: not region(point)
def intersection(region1, region2):
return lambda point: region1(point) and region2(point)
def difference(region1, region2):
return intersection(region1, inverse(region2))
def target(max_distance, min_distance, friend):
donnut_region = difference(circle(max_distance), circle(min_distance))
friend_region = shift(circle(min_distance), friend)
return difference(donnut_region, friend_region)
region = target(3, 1, Point(2,2))
print region(Point(x=1,y=1))
Point = Struct.new(:x, :y)
def Point(hash)
Point.new(hash[:x], hash[:y])
end
def Region(&block)
block.tap{|b|b.instance_eval{alias :include? :call}}
end
def circle(distance)
Region{|point| (point.x ** 2.0 + point.y ** 2.0) ** (1/2.0) < distance}
end
def shift(region, position)
Region{|point| region.include? Point(x: point.x - position.x, y: point.y - position.y)}
end
def inverse(region)
Region{|point| !region.include? point}
end
def intersection(region1, region2)
Region{|point| region1.include?(point) && region2.include?(point)}
end
def difference(region1, region2)
intersection(region1, inverse(region2))
end
def target(max_distance, min_distance, friend)
donnut_region = difference(circle(max_distance), circle(min_distance))
friend_region = shift(circle(min_distance), friend)
difference(donnut_region, friend_region)
end
region = target(3, 1, Point(x:2,y:2))
puts region.include?(Point(x:1,y:1))
import CoreGraphics
typealias Position = CGPoint
typealias Distance = CGFloat
let minimumDistance : Distance = 2.0
func inRange(target: Position, ownPosition: Position, friendly: Position, range: Distance) -> Bool {
let dx = ownPosition.x - target.x
let dy = ownPosition.y - target.y
let friendlyDx = friendly.x - target.x
let friendlyDy = friendly.y - target.y
return sqrt(dx * dx + dy * dy) <= range && sqrt(dx * dx + dy * dy) >= minimumDistance && (sqrt(friendlyDx * friendlyDx + friendlyDy * friendlyDy) >= minimumDistance)
}
inRange(Position(x: 4.0, y:4.0), Position(x:0.0, y:0.0), Position(x:50.0, y:50.0), 10.0)
typealias Region = Position -> Bool
func circle(radius: Distance) -> Region {
return { point in sqrt(point.x * point.x + point.y * point.y) <= radius }
}
circle(3.0)(Position(x:1.0, y:1.0))
func shift(offset: Position, region: Region) -> Region {
return { point in
let shiftedPoint = Position(x: point.x + offset.x, y: point.y + offset.y)
return region(shiftedPoint)}
}
func intersection(region1 : Region, region2 : Region) -> Region {
return { point in region1(point) && region2(point) }
}
func invert(region: Region) -> Region {
return { point in !region(point) }
}
func difference(region: Region, minusRegion: Region) -> Region {
return intersection(region, invert(minusRegion))
}
func inRangeF(ownPosition: Position, target: Position, friendly: Position, range: Distance) -> Bool {
let targetRegion = shift(ownPosition, difference(circle(range), circle(minimumDistance)))
let friendlyRegion = shift(friendly, circle(minimumDistance))
let resultRegion = difference(targetRegion, friendlyRegion)
return resultRegion(target)
}
inRangeF(Position(x: 4.0, y:4.0), Position(x:0.0, y:0.0), Position(x:50.0, y:50.0), 10.0)
(let [
circle (fn[r] (fn[p] (< (Math/sqrt (+ (* (p :x) (p :x)) (* (p :y) (p :y)))) r)))
shift (fn[reg pos] (fn[p] (reg {:x (- (p :x) (pos :x)) :y (- (p :y) (pos :y))}) ))
inverse (fn[reg] (fn[p] (not (reg p))))
intersection (fn[reg1 reg2] (fn[p] (and (reg1 p) (reg2 p))))
difference (fn[reg1 reg2] (intersection reg1 (inverse reg2)))
target (fn[max_distance min_distance friend]
(let [donnut (difference (circle max_distance) (circle min_distance))
friendly (shift (circle min_distance) friend)]
(difference donnut friendly)))
]
(let [region (target 3 1 {:x 2 :y 2})]
(printf "%s%n" (region {:x 1 :y 2}))
(printf "%s%n" (region {:x 2 :y 2}))
(printf "%s%n" (region {:x 2 :y -2}))))
; java -cp clojure-1.7.0.jar clojure.main regions.clj
circle = fn radius -> fn p -> :math.sqrt( :math.pow(p[:x], 2) + :math.pow(p[:y], 2) ) < radius end end
offset = fn reg, pos -> fn p -> reg.([x: p[:x] - pos[:x], y: p[:y] - pos[:y]]) end end
inverse = fn reg -> fn p -> !reg.(p) end end
intersection = fn reg1, reg2 -> fn p -> reg1.(p) && reg2.(p) end end
difference = fn reg1, reg2 -> intersection.(reg1, inverse.(reg2)) end
target = fn max_distance, min_distance, friend ->
donnut_region = difference.(circle.(max_distance), circle.(min_distance))
friend_region = offset.(circle.(min_distance), friend)
difference.(donnut_region, friend_region)
end
region = target.(3, 1, [x: 2, y: 2])
IO.inspect region.(x: 1, y: 1) # => true
IO.inspect region.(x: 2, y: 2) # => false
IO.inspect region.(x: 2, y: -2) # => true
package main
import (
"fmt"
"math"
)
type Point struct{ X, Y float64 }
type Distance float64
type Region func(Point) bool
func main() {
circle := func(radius Distance) Region {
return func(p Point) bool { return math.Sqrt(p.X*p.X+p.Y*p.Y) <= float64(radius) }
}
shift := func(reg Region, pos Point) Region {
return func(p Point) bool { return reg(Point{p.X - pos.X, p.Y - pos.Y}) }
}
intersection := func(reg1, reg2 Region) Region {
return func(p Point) bool { return reg1(p) && reg2(p) }
}
invert := func(reg Region) Region { return func(p Point) bool { return !reg(p) } }
difference := func(reg1, reg2 Region) Region { return intersection(reg1, invert(reg2)) }
target := func(max_distance, min_distance Distance, friend Point) Region {
donnut_region := difference(circle(max_distance), circle(min_distance))
friend_region := shift(circle(min_distance), friend)
return difference(donnut_region, friend_region)
}
region := target(3, 1, Point{X: 2.0, Y: 2.0})
fmt.Printf("%v\n", region(Point{X: 1.0, Y: 1.0})) // => true
fmt.Printf("%v\n", region(Point{X: 2.0, Y: 2.0})) // => false
fmt.Printf("%v\n", region(Point{X: 2.0, Y: -2.0})) // => true
}
// $ go run regins_lambda.go
type Point = (Double, Double)
type Region = Point -> Bool
type Distance = Double
circle :: Distance -> Region
circle r = \ (x, y) -> sqrt(x^2 + y^2) < r
shift :: Region -> Point -> Region
shift region (x, y) = \ (x', y') -> region (x - x', y - y')
inverse :: Region -> Region
inverse region = not . region
intersection :: Region -> Region -> Region
intersection region1 region2 = \ point -> region1 point && region2 point
difference :: Region -> Region -> Region
difference region1 region2 = region1 `intersection` inverse region2
target :: Distance -> Distance -> Point -> Region
target max_distance min_distance friend =
let donnut = circle max_distance `difference` circle min_distance
friendly = circle min_distance `shift` friend
in donnut `difference` friendly
-- $ ghci
-- :l regions
-- > let region = target 3 1 (2, 2)
-- > region (1, 1)
-- True
-- > region (2, 2)
-- False
-- > region (2, -2)
-- True
import :math, only: [sqrt: 1, pow: 2]
pow2 = &pow(&1, 2)
circle = fn radius -> &(sqrt( pow2.(&1[:x]) + pow2.(&1[:y]) ) < radius) end
offset = fn reg, pos -> &(reg.([x: &1[:x] - pos[:x], y: &1[:y] - pos[:y]])) end
inverse = fn reg -> &(!reg.(&1)) end
intersection = fn reg1, reg2 -> &(reg1.(&1) && reg2.(&1)) end
difference = &(intersection.(&1, inverse.(&2)))
target = fn max_distance, min_distance, friend ->
donnut_region = difference.(circle.(max_distance), circle.(min_distance))
friend_region = offset.(circle.(min_distance), friend)
difference.(donnut_region, friend_region)
end
region = target.(3, 1, [x: 2, y: 2])
IO.inspect region.(x: 1, y: 1) # => true
IO.inspect region.(x: 2, y: 2) # => false
IO.inspect region.(x: 2, y: -2) # => true
from collections import namedtuple
P = namedtuple('P', ['x', 'y'])
circle = lambda radius: lambda p: (p.x ** 2. + p.y ** 2.) ** (1/2.) < radius
shift = lambda reg, pos: lambda p: reg(P(x=p.x-pos.x, y=p.y-pos.y))
inverse = lambda reg: lambda p: not reg(p)
intersection = lambda reg1, reg2: lambda p: reg1(p) and reg2(p)
difference = lambda reg1, reg2: intersection(reg1, inverse(reg2))
target = lambda max_distance, min_distance, friend: (
lambda donnut_region, friend_region: difference(donnut_region, friend_region))(
donnut_region = difference(circle(max_distance), circle(min_distance)),
friend_region = shift(circle(min_distance), friend))
region = target(3, 1, P(2,2))
print region(P(x=1,y=1)) # => True
print region(P(x=2,y=2)) # => False
print region(P(x=2,y=-2)) # => True
Point = Struct.new(:x, :y)
P = -> hash { Point.new(hash[:x], hash[:y]) }
CIRCLE = -> radius { -> p { (p.x ** 2.0 + p.y ** 2.0) ** (1/2.0) < radius } }
SHIFT = -> reg { -> pos { -> p { reg[P[x: p.x - pos.x, y: p.y - pos.y]] } } }
INVERSE = -> reg { -> p { !reg[p]} }
INTERSECTION = -> reg1 { -> reg2 { -> p { reg1[p] && reg2[p] } } }
DIFFERENCE = -> reg1 { -> reg2 { INTERSECTION[reg1][INVERSE[reg2]] } }
TARGET = -> max_distance, min_distance, friend {
donnut_region = DIFFERENCE[CIRCLE[max_distance]][CIRCLE[min_distance]]
friend_region = SHIFT[CIRCLE[min_distance]][friend]
DIFFERENCE[donnut_region][friend_region]
}
REGION = TARGET[3, 1, P[x: 2, y: 2]]
p REGION[P[x: 1, y: 1]] # => true
p REGION[P[x: 2, y: 2]] # => false
p REGION[P[x: 2, y: -2]] # => true
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
class Region:
def __init__(self, area):
self.area = area
def __call__(self, p):
return self.area(p)
def __invert__(self):
return Region(lambda p: not self(p))
def __and__(self, other):
return Region(lambda p: self(p) and other(p))
def __sub__(self, other):
return self & ~other
def shift(self, point):
return Region(lambda p: self(Point(x=p.x-point.x, y=p.y-point.y)))
def circle(distance):
return Region(lambda p: (p.x ** 2. + p.y ** 2.) ** (1/2.) < distance)
def target(max_r, min_r, friend):
return circle(max_r) - circle(min_r) - circle(min_r).shift(friend)
region = target(3, 1, Point(2, 2))
print region(Point(1, 2))
print region(Point(2, 2))
print region(Point(2, -2))
Point = Struct.new(:x, :y)
class Region
def initialize(&block)
@area = block
end
def include?(p)
@area[p]
end
def shift(point)
Region.new { |p| include?(Point.new(p.x - point.x, p.y - point.y)) }
end
def !
Region.new { |p| !include?(p)}
end
def &(other)
Region.new { |p| include?(p) && other.include?(p) }
end
def -(other)
self & !other
end
end
def circle(distance)
Region.new { |p| (p.x ** 2.0 + p.y ** 2.0) ** (1/2.0) < distance }
end
def target(max_r, min_r, friend)
circle(max_r) - circle(min_r) - circle(min_r).shift(friend)
end
region = target 3, 1, Point.new(2, 2)
puts region.include? Point.new(1, 2)
puts region.include? Point.new(2, 2)
puts region.include? Point.new(2, -2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment