4 ms·
Python: import math def Circle(x, y, r): return (lambda visitCircle, visitRectangle : visitCircle(x, y, r)) def Rectangle(x, y, w, h):
by xaedes 6y ago
Python:
import math
def Circle(x, y, r):
return (lambda visitCircle, visitRectangle : visitCircle(x, y, r))
def Rectangle(x, y, w, h):
return (lambda visitCircle, visitRectangle : visitRectangle(x, y, w, h))
def area(shape):
return shape(
lambda x, y, r : math.pi * r * r,
lambda x, y, w, h : w * h
)
exampleCircle = Circle(2, 1.4, 4.5)
exampleRectangle = Rectangle(1.3, 3.1, 10.3, 7.7)
print(area(exampleCircle))
print(area(exampleRectangle))
# 63.61725123519331
# 79.31
- scaraffe 6y agocan someone explain how this works? or where I can learn more about this.
- ajoseps 6y agoI think it's best understood if you work backwards from the print calls 1. print is fairly straightforward, prints to stdout what is inputted 2. def area(shape) returns the result of shape call with the two lambda parameters representing the area of a circle as the first parameter, and the second representing the area of a rectangle. 3. def Circle(x,y,r) & def Rectangle(x, y, w, h) are functions which return a lambda that both accepts two parameters, visitCircle and visitRectangle. visitCircle corresponds to the lambda x, y, r : math.pi * r * r in def area(shape). visitRectangle corresponds to the lambda x, y, w, h : w *h in def area(shape). So the def Circle(x, y, r) returns a lambda that takes as input these two formulas, but chooses the formula for calculating a circle's area, whereas def Rectangle(x, y, w, h) takes as input the same two formulas, but chooses the formula for calculating a rectangle's area.
- deleted 6y ago[deleted]
- kaba0 6y agoThis is basically what the blog post explains, though without some Haskell knowledge it is probably hard to understand. (Sorry if I explain something you already know) The basic idea is that types can be “recreated” in an untyped way with only functions. It is also important to note the distinction between sum types and product types. A sum type is basically a (disjunct) set of types, for example Shape is a sum type on Rectangles and Circles (in this case only these things are considered the available shapes and every shape is either one or another). A product type is more straight-forward, basically any struct/class with multiple fields is an example, for example Circle is a product type with a radius and an x and y coord of its centerpoint. For example here the two-ary methods represents the two types: return (lambda visitCircle, visitRectangle : visitCircle(x, y, r)) Is going to represent circles, by awaiting two functions that work as constructors, and dispatching to the first one. Rectangle is similarly defined, only dispatching to the second function. The part that corresponds to pattern matching/the second dispatch is basically where we would like to use our sum-types (either a circle or a rectangle). It provides both implementation in the form of a pair of functions, the first one corresponds to the circle’s area-definition the second to the rectangle’s. The “magic” happens at calling area(exampleSomething). The area function will return as seen a pair of functions, basically every possible implementation on the possible types. Now that pair of functions will go to either a Circle ‘constructor’ function or a Rectangle one, and as we defined those, it will use up respectively the first or the second function in the pair based on its “type”. Also note that the correct arity of parameters will be passed to the selected function.
- nick__m 6y agoThe good explanations you received lack a fundamental definition that will help those without formal CS education or some experience in FP to understand that code : A lambda is a function that take two arguments: - a list of arguments A - a block of code C And return an anonymous function having the arguments in A and C as a body. In python lambda is an expression and the syntax is : #A is the part before the : and C the part after lambda a1 a2 a3 : a1 + a2 + a3 A more formal definition is available in the Racket guide https://docs.racket-lang.org/guide/syntax-overview.html#%28part._.Anonymous_.Functions_with_lambda%29 https://docs.racket-lang.org/guide/syntax-overview.html#%28p...
- chombier 6y ago1. each case of the pattern matching is encoded by a lambda (the ones passed to "shape" in function "area") 2. each possible shape instance is a function that will accept these case lambdas, picking the one corresponding to it and passing its constructor arguments to it 3. the constructors ("Circle", "Rectangle") create the shape instances
- mdoms 6y agoSo every shape now has to reference every other shape? If I want to add a new shape I not only have to define the shape function, def Triangle(a,b,c): return (lambda visitCircle, visitRectangle, visitTriangle : visitTriangle(a, b, c)) and update the area function, I also need to update every existing type like def Rectangle(x, y, w, h): return (lambda visitCircle, visitRectangle, visitTriangle : visitRectangle(x, y, w, h)) Am I understanding this correctly? How is this a win? What if I have a hundred different shapes, now every shape definition is just a list of a hundred parameters and hopefully I called the correct one in my copy&paste-fest.
- Twisol 6y agoThat's why we usually group all of these handlers into a single Visitor interface. Then you only add one class and one extra method to the Visitor, and all the other variants stay the same. You're brushing up against the so-called "expression problem", though, where you can choose between adding types easily or adding algorithms easily, but not usually both.
- h_anna_h 6y agoHere you go import math def Circle(x, y, r): return (lambda d : d['visitCircle'](x, y, r)) def Rectangle(x, y, w, h): return (lambda d : d['visitRectangle'](x, y, w, h)) def area(shape): return shape({ 'visitCircle': lambda x, y, r : math.pi * r * r, 'visitRectangle': lambda x, y, w, h : w * h }) exampleCircle = Circle(2, 1.4, 4.5) exampleRectangle = Rectangle(1.3, 3.1, 10.3, 7.7) print(area(exampleCircle)) print(area(exampleRectangle)) # 63.61725123519331 # 79.31