The functional way to write these methods in F #

To calculate the area of โ€‹โ€‹the square and the circle, I defined the following type:

type Square = {width: float; length: float;} with member this.area = this.width * this.length member this.perimeter = (this.width + this.length) * 2. type Circle = {r:float} with member this.area = System.Math.PI * this.r * this.r member this.perimeter = 2. * System.Math.PI * this.r let s1 = {width = 3.; length = 4.} let c1 = {r = 8.3} printfn "%A" s1 printfn "The area of s1 is: %A" s1.area printfn "The perimeter of s1 is: %A" s1.perimeter printfn "%A" c1 printfn "The area of c1 is: %A" c1.area printfn "The perimeter of c1 is: %A" c1.perimeter 

When I read this article: http://fsharpforfunandprofit.com/posts/type-extensions/

It states:

  • Methods do not work well with output type
  • Methods do not work well with higher order functions

So, a plea for you, new to functional programming. Do not use methods if you can, especially when you are studying. They have a crutch that will stop you, taking full advantage of functional programming.

Then what is a functional way to solve this problem? or what is the F # ideal way?


Edit

After reading the F # Component Design Guide (curtsy to @VB) and the @JacquesB comment, I believe that implementing a member method inside this type is the easiest, internal way:

 type Square2 (width: float, length: float) = member this.area = width * length member this.perimeter = (width + length) * 2. 

(This is almost identical to my original Square type - this Square2 only saves the prefix seveal this. As in this.width , this.length .)

Again, the F # Component Design Guide is quite helpful.

+6
source share
2 answers

A more functional way to do this would be to create a Shape discriminated union where Square and Circle would be his cases. Then create the area and perimeter functions by taking a Shape and using pattern matching:

 type Shape = | Square of Width: float * Length: float | Circle of R: float let area = function | Square (width, length) -> width * length | Circle r -> System.Math.PI * r * r let perimeter = function | Square (width, length) -> (width + length) * 2. | Circle r -> 2. * System.Math.PI * r let s1 = Square(Width = 3., Length = 4.) let c1 = Circle(R = 8.3) printfn "%A" s1 printfn "The area of s1 is: %A" (area s1) printfn "The perimeter of s1 is: %A" (perimeter s1) printfn "%A" c1 printfn "The area of c1 is: %A" (area c1) printfn "The perimeter of c1 is: %A" (perimeter c1) 
+8
source

There is a more functional way that @svick describes well, but also see the F # Component Design Guide >

  • Use properties and methods for type-specific operations.

This is called specifically because some people from functional background programming avoid using object-oriented programming together, preferring a module containing a set of functions that define internal functions of a type (for example, the length foo rather than foo.Length). But see also the following bullet. In general, in F #, the use of object-oriented programming is preferred as a device software development. This strategy also provides some of the benefits of tools, such as Visual Studios "Intellisense," to discover methods on the enter "dotting into" object.

  • Consider the types of interfaces for representing related groups of operations that can be implemented in several ways.

In F #, there are several ways to represent a dictionary of operations, such as using tuples of functions or function records. In general, we recommend using interface types for this.

So, according to these recommendations, the IShape interface with the Area and Perimeter members is the recommended method for the F # component, despite the fact that in general there is a more โ€œfunctionalโ€ way.

+1
source

Source: https://habr.com/ru/post/986977/


All Articles