기능적으로 프로그램 설계 #1: 핵심 개념 및 볼링 예

14600 단어 designfunctional
오늘날 함수식 프로그래밍은 소프트웨어 공학계에서 광범위한 관심을 받고 있다.우리는 함수식 프로그래밍이 가져다 주는 이점에 대해 많은 글과 열정적인 토론을 하고 있다.
나는 함수식 프로그래밍을 믿고 공헌하고 싶다.
함수식 프로그래밍이 도대체 무엇인지 이야기하는 내용이 많지만, 나는 여전히 많은 초기 채택자들이 명령식이나 대상 프로그램에 적합한 사고 과정을 이용하여 프로그램을 설계하는 것을 보았다.
그래서 예민하지 않은 사람이 되기 어렵다.
그래서 이 일련의 문장에서 나는 함수 모델로 프로그램 뒤의 사고 과정을 작성하는 것을 토론할 것이다.너는 어디서부터 시작했니?주요 전략은 무엇입니까?무엇이 문제 해결 모델입니까?
NDC 컨퍼런스에서 나온 이 사진이 진실이라고 생각하지만, 도움이 되지 않는다고 본다.

우리 그것을 분해합시다.

핵심 개념


기능적 사고의 핵심 사상은 성명적 코드다.
성명성 코드는 무엇입니까?잘 물었습니다.
이것은 함수의 수학 정의이다

In mathematics, a function[note 1] is a binary relation between two sets that associates every element of the first set to exactly one element of the second set. Typical examples are functions from integers to integers, or from the real numbers to real numbers.


기본적으로 함수는 입력과 출력 사이의 정적 매핑이다.함수는 어떻게 결과를 얻느냐에 무관심하다.가능한 모든 사례에 대해 당신은 백만 위안이 있을 수 있습니다.이것은 여전히 함수다.
그래서 함수식 프로그래밍에서 우리는
Problem(inputs) => answer
본문에서 우리는 bowling kata를 예로 사용할 것이다.
그래서 우리가 말하고 싶은 것은 함수가 하나 있다.
Bowling(game) => score
이렇게요컨대 이것은 함수식 프로그래밍이다.
우리는 이 기능을 실현할 수 있도록 설계가 하나 있다.
잠깐만...
그럼, 이 함수에서 모든 논리를 쓴다는 뜻입니까?우리는 최종적으로 1000줄의 코드를 얻을 수 있습니까?이게 정말 이해가 안 돼요?
이제 우리는 튼튼한 부분으로 들어간다.어떻게 시스템을 붕괴시킵니까?

문제를 해명하다


명령식과 대상을 향한 범례에서 우리는 많은 모델, 계발식과 표준적인 사고 과정을 통해 문제를 분해한다.
예를 들어 가장 기본적인 대상 프로그래밍은 하위 시스템을 정의하는 것이다.그 다음에 우리는 이 대상에 대해 실행할 수 있는 동작을 정의한 다음에 그것을 한데 연결시킨다.
많은 디자인 모델과 전략이 이 점을 실현할 수 있다.그럼에도 불구하고 대상을 대상으로 하는 기본 구조 블록과 사고 과정은 비교적 작은 대상을 정의하고 그것들을 협동하여 일하게 하는 것이다.
그러나 우리는 어떻게 함수식 프로그래밍 모델에서 시스템을 분해합니까?
우선, 우리는 impure part of a system와 순수 부품 사이에 경계를 세워야 한다.이것은 오늘의 초점이 아닐 것이다.우리는 시스템의 순수한 부분을 어떻게 분해하는지에만 관심을 기울일 것이다.
그래.우리는 어떻게 해야만 그것을 분해할 수 있습니까?
답은 같다: 더 많은 함수를 써라!!

기다리다이것은 도움이 되지 않는다.어떤 기능입니까?더 많은 기능이 모든 문제를 해결하는 방법입니까?
자...
네, 더 밝힐게요.거래는 이렇습니다.

Let say you try to write a function between problem -> solution. If it is hard to write a function problem -> solution, then we just need to figure out any C that is easier to write a function problem -> C and C -> solution. Then, we write two easy functions


이것이 바로'더 많은 함수를 작성하라'는 뜻이다.
생각하는 과정은 간단한 것 같지만 이해하기 어렵다.
이 시리즈에서 나는 함수 모드에서 어떻게 프로그램을 설계하는지 설명할 것이다. 몇몇 프로그래밍kata를 해결하는 것부터 시작할 것이다.

볼링 탑


함수bowling kata의 목적은 함수를 작성하는 것이다.
getScore(game) -> score
단지 첫눈에 이 함수가 상당히 길고 복잡할 것이라는 것을 나는 알았다.
나는 그것을 뜯기로 결정했다.
이 질문을 사용하십시오: 무엇이 이런 데이터입니까?
  • 데이터 a에 따라 볼링 경기 점수를 계산하는 것이 더 간단하다.
  • 볼링 경기의 데이터를 계산하는 것이 더욱 간단하다.
  • (일반적으로 두 속성을 동시에 만족시키기는 어렵다. 따라서 현실 세계에서 한 속성만 직감적으로 만족시키고 다른 속성을 만족시키는지 테스트할 수 있다)
    그래서 나는
    만약 내가 모든 볼링 프레임의 득점을 한다면, 나는 그것을 합쳐서 게임 득점을 만들 수 있다.
    그래서 나는 매 경기의 점수를 중간 데이터로 선택했다.
    const solution = (game) => somethingICannotFigureOut(game)
    // Become
    const solution = (game) => sum(frameScores(game)))
    
    나는 sum가 실현하기 쉽다는 것을 알고 frameScores가 더욱 쉽게 실현될 것이라고 생각한다.
    지금 나에게 남겨진 것은 실시frameScores다.
    그러나 우리가 시작하기 전에 일치를 유지하기 위해 나는 게임의 데이터 구조를 분명히 할 것이다.
    export type NumberScore = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
    export type StrikeFrame = [10, null]
    export type ScoreFrame = [NumberScore, NumberScore]
    export type NormalFrame = StrikeFrame | ScoreFrame
    export type LastFrame = [NumberScore, NumberScore, NumberScore | null]
    export type NextFrames = Frame[]
    export type Frame = NormalFrame | LastFrame
    export type Game = [
      NormalFrame,
      NormalFrame,
      NormalFrame,
      NormalFrame,
      NormalFrame,
      NormalFrame,
      NormalFrame,
      NormalFrame,
      NormalFrame,
      LastFrame
    ]
    
    이것은 데이터의 형상이다.하나의 게임은 9개의 노멀프레임과 1개의 라스트프레임으로 구성된 원조다.
    내가 실현하려고 시도했을 때 frameScores, 나는 한꺼번에 실현하기 어렵다는 것을 발견했다.나는 아무것도 생각하지 못했다.
    그래서 좀 더 세분화하기로 했습니다.
    AframeScores는 매 프레임의 점수이기 때문에 나는 매 프레임의 점수를 계산하는 방법이 필요하다.
    어떻게 해야 합니까?이곳의 규칙과 논리는 무엇입니까?
    각 프레임에서 투수는 최대 두 번 모든 핀을 쓰러뜨리려고 시도한다.기본적으로 프레임 점수를 계산하는 방법은 네 가지가 있습니다.
  • 만약 두 번의 시도에서 그가 그들을 쓰러뜨리지 못했다면 이 프레임의 득점은 그가 두 번의 시도에서 쓰러진 바늘의 총수이다.
  • 만약 그가 두 번의 시도에서 그들을 모두 쓰러뜨렸다면 이것은'준비'라고 불린다. 그의 프레임 득점은 10에 그가 다음 던질 때(그의 다음 라운드) 쓰러진 바늘 수를 더한 것이다.
  • 만약 그가 처음으로 프레임에서 모든 핀을 쓰러뜨리려고 시도한다면 이것은'타격'이라고 불린다.그의 라운드가 끝났고, 그의 프레임 득점은 10에 다음 두 라운드에서 쓰러진 핀을 더한 간단한 총수였다.
  • 투수가 마지막(10번째 프레임에서 예비구 또는 스트라이크를 얻으면 투수는 각각 한 개 또는 두 개의 유상구를 더 던질 수 있다.이 추가 주사위는 같은 라운드의 일부분이 될 것이다.만약 상품 투척이 모든 큰 바늘을 쓰러뜨렸다면 이 과정은 중복되지 않을 것이다. 상품 투척은 마지막 프레임의 점수를 계산하는 데만 사용된다.
  • 그게 규칙이야.붕괴하고 싶습니다frameScore.제가 뭘 할 수 있을까요?
    같은 질문을 반복합니다. 이런 데이터는 무엇입니까?
  • 데이터 A에 따라 단일 프레임 점수를 계산하는 것이 더 간단합니다.
  • 볼링 경기에서 데이터 A를 계산하는 것이 더 간단하다.
  • 그래서 나는 무엇이 데이터 집합이라고 생각한다.
    나는 A가 하나의 이유라는 것을 발견했다
  • 이 프레임에서 분리된 핀 수량
  • 다음 두 권
  • 에서 분리된 핀 수량
    만약 내가 이 모든 데이터를 가지고 있다면, 나는 이렇게 쉽게 실현할 수 있다frameScore
    // Given frame and nextRolls
    switch (getFrameType(frame)) {
        case FrameType.LastFrame:
          return frame[0] + frame[1] + (frame[2] || 0)
        case FrameType.Score:
          return frame[0] + frame[1]
        case FrameType.Spare:
          return frame[0] + frame[1] + nextRolls[0]
        case FrameType.Strike: {
          return frame[0] + nextRolls[0] + nextRolls[1]
        }
      }
    
    지금 나는 그것의 실현이 이미 충분히 간단하다고 생각한다. 그래서 나는 여기서 나의 붕괴를 끝냈다.
    거래가 성립되었다!!나는 프로그램 설계를 하나 가지고 있다.
    생각을 되돌아보도록 하겠습니다.
  • 함수BowlingScore(game) => score를 원하지만, 나는 그것이 너무 쓰기 어렵다고 생각한다.
  • 그래서 저는 쓰기 쉬운 방식으로 데이터 ASomething(game) => AAnother(A) => score를 제시했습니다.A는 각 프레임의 분수입니다.
  • 지금 나는 함수를 하나 원한다. 하나의 게임을 정하면 각 게임의 점수를 계산할 수 있다.나는 여전히 쓰기가 너무 어렵다고 생각한다.
  • 그래서 저는 쓰기 쉬운 방식으로 데이터 ASomething(game) => AAnotherThing(A) => frameScore를 제시했습니다.이것은 프레임 자체와 다음 두 개의 볼륨으로 구성된 데이터 집합이다.
  • 그래서 마지막에 저희가 통과할 수 있어요.
  • gameScore = game |> break_into_frame_and_two_rolls 
    |> Map(frameScore) |> sum
    
    내가 이 모든 것을 실현하려고 시도했을 때, 나는 모든 것이 충분히 간단하고, 작성하고 추리할 수 있다는 것을 발견했다.
    결과를 보고 싶으세요?TypeScript의 구현을 찾을 수 있습니다here.Scala에서 구현here을 찾을 수 있습니다.

    결론


    내가 쓴 바와 같이 순수 함수 영역에서 함수 프로그래밍 디자인의 사고 과정은 다음과 같이 간단하게 표현할 수 있다.

    Let say you try to write a function between problem -> solution. If it is hard to write a function between problem -> solution, then we just need to figure out any C that is easier to write a function between problem -> C and C -> solution. Then we simply write two easy functions


    이렇게이것은 매우 간단하지만 매우 효과적인 문제를 사고하는 방식이다.
    나는 예를 들어 이 문제를 반복해서 물어본 결과, 그리고 내가 최종적으로 어떤 프로젝트를 얻었는지 보여 주었다.
    이 질문을 반복하면 어떤 프로그램 설계가 나올지 흥미롭다.이것은 간단하면서도 유력한 문제다.다음 글에서 더 많은 내용을 보여 드리겠습니다.
    나는 너희들이 왜 함수식 프로그래밍 디자인이'더 많은 함수를 작성할 수 있다!!'처럼 간단한지 이제 이해하기를 바란다.😄
    읽어주셔서 감사합니다!!
    TypeScript 전체 구현: https://github.com/chrisza4/functional-bowling-ts
    Scala 전체 구현: https://github.com/chrisza4/functional-bowling-scala

    몇 가지 관점:


    너는 이것이 명령식 프로그래밍과 무엇이 다른지 알고 싶을지도 모른다.
    약간의 다른 사고방식을 가질 수 있도록 생각할 필요가 있다.
    가장 가능성이 높은 것은 네가 이런 상황에 빠질 것이다.
  • 예비 프레임 점수는 조금 더 많은 프레임
  • Strike frame score는 조금 더 많은 프레임워크
  • 하지만 이 점이 더 많은 것은 어디에서 왔을까?그것은 게임의 또 다른 프레임에서 왔기 때문에 하나의 프레임 점수가 전체 게임에 접근할 수 있어야 한다고 자연스럽게 생각하는 것은 옳지 않다.
    내가 본 대부분의 실현은 단지 전체 게임 환경을 하나의 대상에 끼워 넣는 것일 뿐이다.gameScoreframeScore 방법은 모두 완전한 게임 상하문을 사용하는데 단지'조금 더'데이터에 접근하기 위해서이다.
    기능 사고방식에서 함수frameScore와 입력을 생각하면 접근이 제한될 수 있다.
    이런 방법을 사용하여 대상을 대상으로 하는 코드를 작성하는 것은 가능하다.Typescript 구현 라이브러리에서 완성했습니다.가보셔도 됩니다.
    주요한 차이는 그것이 만들어낸 코드가 아니다.다른 점은 사유 과정에 있다.당신은 데이터 + 조작을 식별해서 복잡한 논리를 분해하고 대상을 만들 수 있습니까?아니면 해결 방안에 더 가까운 데이터 구조를 식별함으로써 복잡한 논리를 분해하는가?
    함수식 사고방식은 함수식 프로그래밍 언어를 사용하지 않아도 도움이 될 수 있습니다.

    좋은 웹페이지 즐겨찾기