Go 함수형 프로그래밍

박재훈·2022년 11월 5일
1

GO

목록 보기
4/19

Summary

Go에서의 간단한 함수형 프로그래밍 구현.
제네릭을 이용하기 때문에 1.18 이상의 버전이 필요하다.

Description

타겟(배열, 슬라이스, 오브젝트 등)을 Shell이라는 단위로 감싼 뒤 그 객체를 여러 함수들을 이용해서 다룬다.
모든 fp 함수들은 *Shell 타입 파라미터를 받으며 F라는 함수를 이용해서 여러 함수들을 연결하여 함수형 프로그래밍을 진행한다.

타입들

함수형 프로그래밍을 좀 더 쉽게 가능케 해주는 여러 타입들이 있다.

// 파이프라인을 이루기 위한 함수
type F func(*Shell) *Shell

// 1개의 제네릭 타입을 받는 함수
type P1[P, R any] func(P) R

// 2개의 제네릭 타입을 받는 함수
type P2[P1, P2, R any] func(P1, P2) R

// 1개의 제네릭 타입 및 인덱스를 받는 함수
type Pi1[P, R any] func(int, P) R

// 2개의 제네릭 타입 및 인덱스를 받는 함수
type Pi2[P1, P2, R any] func(int, P1, P2) R

// 2개의 제네릭 타입 및 인덱스를 받는 void형 함수
type Pi2V[P1, P2 any] func(int, P1, P2)

type A func(any)

함수들

자바스크립트와 좀 유사한 면이 있다.

Map[T, U any](convert Pi1[*T, *U]) F
Filter[T any](f Pi1[*T, bool]) F
Slice[T any](idxes ...int) F
Reduce[T, U any](reducer Pi2[*T, *U, *U]) F
Sort[T any](sorter P2[*T, *T, bool]) F
ArrayCopy[T any]() F
Func[T, U any](f P1[T, U]) F
Some[T any](f Pi1[*T, bool]) F
Every[T any](f Pi1[*T, bool]) F
ForEach[T any](f Pi2V[*T, []T]) F
Reverse[T any]() F
Append[T any](elements []T) F
MapOne[T, U any](f P1[*T, *U]) F

함수들을 연결하는 방법은 2가지가 있다.

  • 파이프
  • 체이닝

파이프

Pipe를 이용해서 F들을 연결할 수 있다.

// `I`는 인풋, `O`는 아웃풋을 의미한다.
Pipe[I, O any](input I, funcs ...F) O

// 순서를 역정렬한 뒤 문자열로 바꾸고 싶다면,
stringArray := fpgo.Pipe[[]int, []string](
    []int{1, 2, 3},
    fpgo.Reverse[int](),
    fpgo.Map[int, string](func(idx int, element *int) *string) {
        s := fmt.Sprintf("No.%d", *element)
        return &s
    }
)
fmt.Println(stringArray) // [No.3 No.2 No.1]

ProcessingPipe를 통해 전/후처리를 할 수 있다.

// processors 배열의 형태: {preprocessor, postprocessor}
ProcessingPipe[I, O any](input I, processors [2]A, funcs ...F) O

// 전/후를 확인하고 싶다면,
fpgo.ProcessingPipe[[]int, []int](
    []int{1, 2, 3},
    [2]fpgo.A{
        func(a any) {
            fmt.Printf("before: %v\n", a)
        },
        func(a any) {
            fmt.Printf("after: %v\n", a)
        },
    },
    functions...,
)

체이닝

위의 Pipe 예시를 체이닝을 통해 구현한 모습은 아래와 같다.

stringArray := fpgo.New([]int{1, 2, 3}).
                    F(fpgo.Reverse[int]()).
                    F(fpgo.Map[int, string](func(idx int, element *int) *string) {
                        s := fmt.Sprintf("No.%d", *element)
                        return &s
                    }).V.([]string)
fmt.Println(stringArray) // [No.3 No.2 No.1]

사용 방법

go get github.com/p9595jh/fpgo
import "github.com/p9595jh/fpgo"
profile
코딩 좋아합니다

0개의 댓글