결합기는 무엇이며 프로그래밍 프로젝트에 어떻게 적용됩니까? (실제 설명)


51

결합기는 무엇입니까?

내가 찾고 있어요:

  • 실용적인 설명
  • 그것들이 어떻게 사용되는지의 예
  • 결합기가 코드의 품질 / 일반성을 향상시키는 방법의 예

찾고 있지 않습니다 :

  • 작업을 수행하는 데 도움이되지 않는 콤비 네이터에 대한 설명 (예 : Y- 콤비 네이터)

조합자는 "부사 (adverb)"와 유사하며, 함수를 취한 다음 다른 함수를 반환하는 함수입니다. 변수 사이에 필요하지 않기 때문에 코드 중복을 제거하는 데 도움이 될 수 있습니다. 몇 가지 유용한 것은 (fg) x = f (g (x)와 같이 두 번 (f) = \ x-> f (f (x)), flip (op)-> \ xy-> y op x, (.)입니다. )), ($)는 ($ 5) <$> [(+1), (* 2)] = [6, 10]에서와 같이 map (<fix> infix)에 도움을 줄 수 있습니다. 카레는 Lisp에서 사용할 수 있습니다 / Python / JavaScript (부분 응용 프로그램 용) 및 uncurry는 Haskell에서 레코드 (튜플)가 필요한 함수에 사용할 수 있습니다. x |> f = fa 인 경우 x |> (길이 &&& sum) |> uncurry (/)는 평균입니다.
— aoeu256

답변:


51

실용적인 관점에서 콤비 네이터는 재미 있고 종종 고급 방식으로 논리 조각을 조합 할 수있는 일종의 프로그래밍 구조입니다. 일반적으로 그것들을 사용하는 것은 실행 가능한 코드를 람다 함수 또는 람다식이라고 불리는 (이전의 이유로) 객체로 묶을 수있는 가능성에 달려 있지만 마일리지는 다를 수 있습니다.

(유용한) 콤비 네이터의 간단한 예는 매개 변수없이 두 개의 람다 함수를 사용하여 순서대로 실행하는 새 함수를 만드는 것입니다. 실제 콤비 네이터는 다음과 같이 일반적인 의사 코드로 보입니다.

func in_sequence(first, second):
  lambda ():
    first()
    second()

이것을 결합 자로 만드는 중요한 것은 두 번째 줄의 익명 함수 (람다 함수)입니다. 전화 할 때

a = in_sequence(f, g)

결과 개체 A는 없는 제 F (), 그리고 g ()를 실행 한 결과, 그러나 만약 시퀀스 F () 및 g ()를 실행하기 위해 나중에 호출 할 수있는 것을 목적으로한다 :

a() // a is a callable object, i.e. a function without parameters

그런 다음 두 코드 블록을 병렬로 실행하는 결합기를 가질 수 있습니다.

func in_parallel(first, second):
  lambda ():
    t1 = start_thread(first)
    t2 = start_thread(second)
    wait(t1)
    wait(t2)

그리고 다시

a = in_parallel(f, g)
a()

멋진 점은 'in_parallel'과 'in_sequence'는 모두 동일한 유형 / 서명을 가진 결합기입니다. 즉, 두 개의 매개 변수가없는 함수 객체를 가져 와서 새로운 것을 반환합니다. 실제로 다음과 같은 것을 쓸 수 있습니다.

a = in_sequence(in_parallel(f, g), in_parallel(h, i))

예상대로 작동합니다.

기본적으로 컴비 네이터를 사용하면 절차적이고 유연한 방식으로 프로그램의 제어 흐름을 구성 할 수 있습니다. 예를 들어, in_parallel (..) 콤비 네이터를 사용하여 프로그램에서 병렬 처리를 실행하는 경우 in_parallel 콤비 네이터 자체의 구현에 이와 관련된 디버깅을 추가 할 수 있습니다. 나중에 프로그램에 병렬 처리 관련 버그가 있다고 생각되면 실제로 in_parallel을 다시 구현할 수 있습니다.

in_parallel(first, second):
  in_sequence(first, second)

한 번의 스트로크로 모든 병렬 섹션이 순차적 인 섹션으로 변환되었습니다!

조합기는 올바르게 사용될 때 매우 유용합니다.

그러나 Y 조합기는 실생활에서 필요하지 않습니다. 자체 재귀 함수를 만들 수있는 결합기이며 Y 조합기를 사용하지 않고도 현대 언어로 쉽게 만들 수 있습니다.


9

Y- 콤비 네이터를 "작업을 수행하는 데 도움이되지 않는"것으로 브랜드화하는 것은 잘못입니다. 많은 경우에 매우 유용하다는 것을 알았습니다. 가장 명확한 경우는 내장 된 해석 언어를 빠르게 부트 스트랩해야하는 경우입니다. 당신이 프리미티브의 최소 세트를 제공하는 경우, 즉 sequence, select, call, consta는 closure allocation, 그것은 완전한 임의의 복잡한 언어를 구축하기위한 이미 충분하다. 재귀에 대한 특별한 지원이 필요하지 않습니다. 고정 소수점 결합기를 통해 추가 할 수 있습니다. 그렇지 않으면 훨씬 더 복잡한 프리미티브가 필요합니다.

결합기의 또 다른 명백한 사례는 난독 화입니다. SKI 미적분학으로 변환 된 코드는 실제로 읽을 수 없습니다. 알고리즘의 구현을 난독 화해야 할 경우 결합기를 사용하는 것을 고려 하십시오 . 여기에 예가 있습니다.

물론 결합기는 기능적 언어를 구현하는 데 중요한 도구입니다. 위의 예와 같이 가장 쉬운 방법은 SKI 또는 이와 동등한 미적분을 사용하는 것입니다. 수퍼 콤비 네이터 는 다른 구현에 사용됩니다. 이 책 은 그것에 대해 깊이 이야기합니다.

많은 프로그래밍 기술과 이론이 여기에 포함되어 있기 때문에 이것은 농담 이지만 매우 신중하게 읽을 가치가있는 농담입니다.


1
@MattFenwick은 간단한 내장형 인터프리터를 필요로하지 않는 경우가 종종 있습니다. 예를 들어, 제 경우에는 통신 프로토콜을 확장하기 위해 디자인해야하는 언어였습니다. 간단한 IPC로는 충분하지 않았으므로 프로토콜은 실행 가능해야했습니다.
— SK-logic

@MattFenwick, 귀하의 질문에 관해서는 : APL 또는 J로 코드를 작성해 볼 수 있습니다. 컴비 네이터가 필수적이므로 코드를 올바르게 적용하는 방법에 대한 아이디어를 얻을 수 있습니다. 또한 포인트 프리 스타일을 읽는 것이 도움이 될 수 있습니다. en.wikipedia.org/wiki/Tacit_programming
— SK-logic

7

약간 파고 들자 나는 StackOverflow 질문, 이 질문의 가까운 사촌 인 "Combinators"(수학자가 아닌 사람들)에 대한 좋은 설명을 발견했습니다 . 답변 중 하나는 지적 레지날드 Braithwaite에의 블로그, Homoiconic (예 : 코드 콤비의 몇 가지 유용한 예제로 연결, K 개의 콤비 루비의 구현, Object#tap- 유용 이유의 예는 페이지를 읽는 방법).

Combinatory Logic 의 Wikipedia 페이지는 전체적으로 결합기를 설명합니다.


이것은 내 질문의 두 번째 글 머리 기호를 다룹니다. 예를 주셔서 감사합니다!

1
이 게시물에는 좋은 링크가 있지만 실제로 질문에 직접 대답하지는 않습니다. 답변은 자체적으로 작성해야하며 필요한 경우 링크를 참조로 사용하십시오.
— Aaronaught
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.