News for hackers. Stuff that matters.
Re:The visitor pattern is essentially the same thing as Chur... by xaedes on Thursday February 04, 2021 @09:17AM (#26025459)
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
Re:The visitor pattern is essentially the same thing as Chur... by mdoms on Thursday February 04, 2021 @01:12PM (#26028101)
So 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.
Re:The visitor pattern is essentially the same thing as Chur... by Twisol on Thursday February 04, 2021 @01:37PM (#26028372)
That'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.

Re:The visitor pattern is essentially the same thing as Chur... by h_anna_h on Thursday February 04, 2021 @03:26PM (#26029394)
Here 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
Re:The visitor pattern is essentially the same thing as Chur... by mdoms on Thursday February 04, 2021 @04:45PM (#26030159)
At this point I have to believe you functional programming guys are just taking the piss.
Re:The visitor pattern is essentially the same thing as Chur... by h_anna_h on Thursday February 04, 2021 @06:45PM (#26031162)
What do you mean? This solves the issue that you mentioned. I am not really a "functional programming guy" myself.
Re:The visitor pattern is essentially the same thing as Chur... by mdoms on Thursday February 04, 2021 @07:23PM (#26031457)
Yes it solves the problem while introducing a hard dependency from a shape to some stringly typed hashmap from who-knows-where.
Re:The visitor pattern is essentially the same thing as Chur... by h_anna_h on Saturday February 06, 2021 @05:22AM (#26045596)
Not really sure what "stringly typed" means. This is just the effect of trying this trick in python.
Re:The visitor pattern is essentially the same thing as Chur... by chombier on Thursday February 04, 2021 @11:06AM (#26026591)
1. 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

Re:The visitor pattern is essentially the same thing as Chur... by scaraffe on Thursday February 04, 2021 @10:51AM (#26026374)
can someone explain how this works? or where I can learn more about this.
Re:The visitor pattern is essentially the same thing as Chur... by ajoseps on Thursday February 04, 2021 @11:02AM (#26026525)
I 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.

Re:The visitor pattern is essentially the same thing as Chur... by kaba0 on Thursday February 04, 2021 @11:10AM (#26026629)
This 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.

Re:The visitor pattern is essentially the same thing as Chur... by nick__m on Thursday February 04, 2021 @06:41PM (#26031133)
The 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#%28p...