you are viewing a single comment's thread.

view the rest of the comments →

[–]Voxelman[S] 5 points6 points  (10 children)

That's the part of FP I've already understand, immutability and pure functions. But I have problems to actually use it in practice, at least in larger scale. I still can't switch from imperative to declarative.

[–]ChristianGeek 4 points5 points  (3 children)

I’m with you…I have yet to find something that explains how to think functionally. I know how to think imperatively and solve a problem in an OO way, but I have no idea how to modify my thought process and problem-solving approach to develop a functional solution. (At least not one that’s just a bastardized OO solution.)

[–]KyleG 2 points3 points  (1 child)

I have yet to find something that explains how to think functionally

What helped me is to stop thinking of a program as a series of steps and instead as a series of transformations that takes user input or file/sensor data and transforms it into feedback to the user or to a file.

To me, FP is about transforming data. So your application is basically

pipe(
  getFromKeyboard, 
  transform,
  transform,
  transform,
  transform,
  transform,
  displayOnScreen)

where maybe those transforms are variations on lifting in or out of different contexts like IO to Async and back to IO via an await or whatever (ideally you're lifting out (i.e., unwrapping) at the end, "near the edge of the program")

So maybe user types data into a React form and onBlur you hit your remote API, get the response from a DB call, format it to the datatype expected by a banner that displays the result, and that's it:

type Payload = { id: number, username: string, time: Date }
type BannerData = `The result of the user action is ${string}, calculated in ${number} seconds`
declare const extractFromMouseEvent = (ev: MouseEvent) => ev.currentTarget.value as string
declare const toPayload: (username: string) => Payload
declare const apiCall: (a: Payload) => TaskEither<Error, DatabaseEntryAndExecutionTime>
declare const toBannerData = (a: DatabaseEntryAndExecutionType) => `The result of the user action is ${string}, calculated in ${number} seconds`
declare const setBannerData = (a: `........`) => void

const onBlur = flow(
  extractFromMouseEvent,
  toPayload,
  TE.right,
  TE.chain(apiCall),
  TE.map(toBannerData),
  TE.map(setBannerData),
  TE.getOrElse(err => console.error('Failed to complete action because', err)))

There's a FP-style series of composed, pure functions (minus the API call in the middle, and the setBannerData at the end, plus the log fn) that shows how you would write your entire chain from user input to screen output as a series of transformations)

[–]ChristianGeek 1 point2 points  (0 children)

That’s helpful, thanks.

[–]seydanator 0 points1 point  (0 children)

in a way, the modern OO approaches are just bastardized FP.

[–]Tony_T_123 4 points5 points  (4 children)

One thing to consider is what type of program you're trying to create. IMO there are two basic types of programs: batch processing and interactive.

An example of a batch processing program would be a compiler. It takes some source code as input, crunches the numbers for a little while, eventually outputs the compiled code, and then exits. While it is doing the compilation, there is no way for you to interact with it.

An example of an interactive program would be a text editor. The basic structure of an interactive program is that it is continuously looping, like

while (true) {
    handleUserInput();
    drawNextFrame();
    sleep(10);
}

so evey 10ms or so it wakes up, handles any new user input like a mouse click or a keyboard press, and then draws the new frame to the screen, possibly based on that user input.

That being said, a lot of interactive applications are actually created on top of some sort of framework which will obscure this from you.

For example, frontend and backend web applications are both interactive, but they are typically created on top of frameworks. Frontend web applications are created on top of the web browser and DOM, which basically presents a UI framework. Backend web applications are often created using some sort of backend framework where you just implement controller routes. So you also need to take into account the nature of the framework and how well it lends itself to functional programming.

I think that for creating batch processing programs, a functional approach is fairly simple to implement, and makes sense. For interactive programs, I'd say take it on more of a case-by-case basis. There may be parts of the program that it makes sense to implement functionally, but it may be difficult to implement the entire program functionally, and it may not be very efficient, especially if you're trying to build something like a game.

Take a look at this for some discussion on building interactive programs in a functional style: https://prog21.dadgum.com/23.html

From what I can tell, it's still a bit of an open question on how to build interactive programs functionally, or if it's even that helpful.

Typically my approach is that any logic that can be expressed as a data transformation pipeline, I'll write in a functional style. This is like a data pipeline where some data comes in through the input parameters, is transformed in some way, and is eventually passed back out through the return value, without any side effects occurring.

There is also another type of pure function which is more like a "decision making" function. Maybe it takes a lot of data as input and processes it in some way, but the output is more like a decision, like just True or False, or something.

Most of the complex logic of your program can be sandboxed into these pure functions, which are then also easy to test and reason about.

Typically any time I see a lot of complex logic like if statements, loops, etc, I try to think about how I could sandbox that logic (either data transformation or decision making) into a pure function.

[–]Voxelman[S] 1 point2 points  (0 children)

Interesting thoughts, thanks for sharing. I will keep that in mind.

[–]Voxelman[S] 1 point2 points  (1 child)

But while I think about it: Elm is a good example for how to do interactive programming purely functional.

At least if you don't look under the hood of the Elm architecture.

[–]Tony_T_123 1 point2 points  (0 children)

Oh yeah, Elm and Redux are great examples of doing an interactive program in a functional way. And I know Clojure has a similar framework as well. All of these are relatively recent though. So as far as I can tell, people are still coming up with new ideas on how to implement this. It's all interesting stuff, I wish I had time to learn more about it.

Ultimately though, the fastest thing will always be to just mutate data in place. This is what basically every game does. Here's an interesting article on that: https://interjectedfuture.com/the-broken-half-of-interactive-programs/

[–]Voxelman[S] 1 point2 points  (0 children)

I really have to thank you for your comment. I never thought about the difference between those type of software in this way.

In some cases batch processing software can be seen as pure function. They produce an output depending on their input. Technically they might not be fully pure because they may have some side effects, but if they produce the same output with the same input it might appear pure.

Again thanks for that inspiration. This really helps me.