파이썬이 함수형 프로그래밍에 왜 좋지 않은가요? [닫은]


324

나는 항상 함수형 프로그래밍이 파이썬에서 이루어질 수 있다고 생각했습니다. 따라서 파이썬 이이 질문 에 대해 언급하지 않았으며, 언급 되었을 때 일반적으로 매우 긍정적이지 않은 것에 놀랐습니다 . 그러나 이에 대한 많은 이유는 없었습니다 (패턴 일치 부족 및 대수 데이터 형식이 언급되었습니다). 그래서 내 질문은 : 왜 파이썬은 함수형 프로그래밍에 좋지 않습니까? 패턴 일치 및 대수 데이터 형식이 부족한 것보다 더 많은 이유가 있습니까? 또는 이러한 개념이 기능 프로그래밍에 매우 중요하여이를 지원하지 않는 언어는 2 차 기능 프로그래밍 언어로만 분류 될 수 있습니까? (함수 프로그래밍에 대한 나의 경험은 상당히 제한되어 있음을 명심하십시오.)


2
2018- Coconut (Python으로 컴파일되는 기능 프로그래밍 언어) 은 Python의 기능 프로그래밍을 향상시킵니다. 또한 IBM의 기사의이 시리즈를 참조하십시오 PAGE1 페이지 2 PAGE3
cssyphus

답변:


393

당신이 참조하는 질문은 어느 언어가 OO와 함수형 프로그래밍을 홍보하는지 묻습니다. 파이썬은 상당히 잘 작동 하더라도 함수형 프로그래밍을 장려 하지 않습니다 .

파이썬 에서 함수형 프로그래밍에 대한 가장 좋은 주장 은 Guido에서 명령형 / OO 유스 케이스를 신중하게 고려하지만 함수형 프로그래밍 유스 케이스는 그렇지 않다는 것입니다. 명령형 Python을 작성할 때 가장 잘 알려진 언어 중 하나입니다. 함수형 파이썬을 작성할 때, BDFL 이없는 일반 언어만큼 추악하고 불쾌합니다 .

기능적 프로그래밍을 장려하는 언어로 전환하거나 OO Python 작성으로 전환 한 경우보다 더 열심히 노력해야한다는 것은 나쁜 일이 아닙니다.

파이썬에서 내가 놓친 기능적인 내용은 다음과 같습니다.


  • 패턴 일치와 테일 재귀가 없다는 것은 기본 알고리즘을 반드시 작성해야한다는 것을 의미합니다. 재귀는 파이썬에서 추악하고 느립니다.
  • 작은 목록 라이브러리와 기능 사전이 없으면 많은 것을 직접 작성해야합니다.
  • 카레 또는 구성에 대한 구문이 없다는 것은 포인트없는 스타일이 인수를 명시 적으로 전달하는 것처럼 구두점으로 가득하다는 것을 의미합니다.
  • 게으른 목록 대신 반복자는 효율성 또는 지속성을 원하는지 여부를 알고 지속성 list을 원하면 주변으로 호출을 분산시켜야 함을 의미합니다 . (반복자는 한번만 사용)
  • 파이썬의 간단한 명령 구문은 간단한 LL1 파서와 함께 if-expression과 lambda-expression에 대한 더 좋은 구문은 기본적으로 불가능하다는 것을 의미합니다. 귀도는 이런 식으로 그것을 좋아하고 나는 그가 옳다고 생각합니다.

5
잃어버린 꼬리 재귀에 +1-루핑 구조가 그것을 대체했지만 파이썬과 스키마 사이에는 여전히 가치가 없습니다.
new123456

5
완전성과 구성에 대한 탁월한 답변. 아아, 강력한 기능적 배경을 가진 많은 답변과 마찬가지로 IMO는 용어를 욕설 적으로 사용합니다. 답변에서 각 개념을 정교하게 설명 할 수는 없지만 "패턴 일치", "기능 사전", "카레 링"또는 "캐릭터"와 같은 용어를 읽을 때 OP (FP 배경에 제한이 있음)에 대한 정확한 정보가 있는지 궁금합니다. 게으른 목록 ".
ThomasH

4
좋은 지적; 해결책은 링크를 추가하는 것입니다. 답변을 편집 할 담당자가 충분합니까? 그렇다면 다양한 개념에 대한 링크를 자유롭게 추가하십시오. 나중에 시간이되면 시작하겠습니다.
Nathan Shively-Sanders 2016

5
나는 이것이 5 살이라는 것을 알고 있지만… 이것은 기능적 언어가 아니라 Haskell 에서 놓친 것들에 관한 것 같습니다 . 예를 들어, 대부분의 ML 및 Lisp 방언 및 자손에는 자동 카레가 없으며, 포인트가없는 스타일을 지나치게 자세하게 표시하고, 게으른 목록이 없습니다. 따라서 게으른 목록 대신 반복자가 있으면 파이썬이 잘못된 기능 언어가됩니다. CaML을 끔찍한 기능적 언어로 만들어야 하지 않습니까?
abarnert

4
@abarnert : Caml에는 라이브러리로 제공되는 지연 목록을 제외한 모든 글 머리 기호가 있습니다. 나는이 대답을 쓸 때 현재 Caml을 사용했으며 현재 F #을 사용합니다. 둘 다 아주 좋은 기능적 언어입니다.
Nathan Shively-Sanders

102

귀도는 여기에 대한 좋은 설명이 있습니다 . 가장 관련성이 높은 부분은 다음과 같습니다.

나는 사람들이 말하거나 생각하는 것에 상관없이 파이썬이 기능적 언어에 의해 크게 영향을받는 것으로 간주하지 않았습니다. 나는 C와 Algol 68과 같은 명령형 언어에 훨씬 익숙했고 함수를 일급 객체로 만들었지 만 파이썬을 함수형 프로그래밍 언어로 보지 않았습니다. 그러나 이전에는 사용자가 목록과 기능으로 더 많은 것을 원한다는 것이 분명했습니다.

...

파이썬을 기능적 언어로 구상하지는 않았지만 클로저 도입은 다른 많은 고급 프로그래밍 기능 개발에 유용했습니다. 예를 들어, 새로운 스타일의 클래스, 데코레이터 및 기타 최신 기능의 특정 측면은이 기능에 의존합니다.

마지막으로, 몇 년 동안 많은 기능적 프로그래밍 기능이 소개되었지만 파이썬에는 여전히 "실제"기능적 프로그래밍 언어에서 볼 수있는 특정 기능이 없습니다. 예를 들어, 파이썬은 특정 종류의 최적화 (예 : 꼬리 재귀)를 수행하지 않습니다. 일반적으로 파이썬은 매우 역동적이므로 Haskell 또는 ML과 같은 기능적 언어에서 알려진 종류의 컴파일 타임 최적화를 수행 할 수 없습니다. 그리고 괜찮습니다.

나는 이것에서 두 가지를 뽑습니다.

  1. 언어를 만든 사람은 실제로 파이썬을 기능적 언어로 생각하지 않습니다. 따라서 "기능적 기능"기능을 볼 수는 있지만 기능적으로 확실한 기능은 볼 수 없습니다.
  2. 파이썬의 동적 특성은 다른 기능적 언어에서 볼 수있는 일부 최적화를 방해합니다. 물론 Lisp는 파이썬만큼이나 역동적이지만 (동적이 아닌 경우) 부분 설명 일뿐입니다.

8
파이썬에서 꼬리 호출 최적화를 잘 수행 할 수 있습니다. 귀도는 그것을 이해하지 못했거나 이해하지 못했습니다.
Jules

26
귀도 반 로섬 (Guido van Rossum) 기능적인 스타일을 좋아하지 않는 것으로 요약 됩니다.
Svante

59
귀도 반 로섬은 기능적 스타일을 이해하지 못하고 파이썬이 왜 필요한지 이해하지 못한다고 말하는 것이 더 정확하다고 생각합니다. 1) 프로그래밍 언어는 기술 스택의 맨 아래에 있으며 그 위에 쌓인 모든 것에 영향을 미칩니다. 2) 다른 소프트웨어와 마찬가지로 기능을 제거하는 것보다 기능을 추가하는 것이 더 쉽습니다. 따라서 언어 디자이너가 이러한 종류의 요청을 비판하는 것이 좋은 품질이라고 생각합니다.
Jason Baker

8
"확실히, Lisp도 역동적입니다."-> 그리고 꼭 필요합니다!
pyon December

6
@ Jules, Python에서 tail call 최적화 사용에 대한 지침을 공유 하시겠습니까? 일부 소스에 대한 포인터가 유용합니다.
David Shaked

52

체계에는 대수적 데이터 유형이나 패턴 일치가 없지만 확실히 기능적인 언어입니다. 함수형 프로그래밍 관점에서 파이썬에 대한 성가신 것들 :

  1. 절름발이 람다. Lambdas는 표현식 만 포함 할 수 있으며 표현식 컨텍스트에서 모든 것을 쉽게 수행 할 수 없으므로 "즉시"정의 할 수있는 기능이 제한되어 있습니다.

  2. if는 표현이 아니라 서술문입니다. 이것은 무엇보다도 내부에 If가있는 람다를 가질 수 없다는 것을 의미합니다. (이것은 Python 2.5에서 3 진으로 수정되었지만 추악하게 보입니다.)

  3. 귀도는 위협 지도, 필터를 제거하고, 절감 한 동안 한 번씩을

다른 한편으로, 파이썬은 어휘 폐쇄, 람다 및리스트 이해 (구도가 인정하는지 여부에 관계없이 실제로 "기능적"개념 임)를 나열합니다. 나는 파이썬에서 "기능적 스타일"프로그래밍을 많이하지만, 그것이 이상적인 것이라고는 거의 말할 수 없다.


3
파이썬에서는 실제로지도, 필터링 및 축소가 필요하지 않습니다. 나는 그것을 사용하여 매우 단순화 된 코드 조각을 아직 보지 못했습니다. 또한 파이썬에서 함수를 호출하는 것은 비용이 많이들 수 있으므로 일반적으로 목록 / 생성기 이해 또는 for 루프를 사용하는 것이 좋습니다.
Jason Baker

2
Nathan Sanders는 다음과 같이 말합니다. "Python은 기능적으로는 잘 작동하지만 기능 프로그래밍을 장려하지는 않습니다." Guido가 Python을 기능적 언어로 사용하기를 원한다면 구현 기능을 충분히 사용하여 버리기 함수를 사용하고 실제로 유용한 방법으로 map / filter / reduce를 사용할 수있는 정도까지 Lambdas를 해치지 않을 것입니다. 다른 한편으로, 기능적인 사람들은 목록 이해력의 놀랍도록 깨어나 기 시작합니다. 바라건대 우리는 둘 중 하나를 선택할 필요가 없습니다.
Jacob B

7
지도와 필터는 목록 이해로 간단하게 대체됩니다. 감소-거의 항상-비효율적이므로 발전기 기능으로 대체해야합니다.
S.Lott 2016 년

13
@ S.Lott 발전기로 리듀서를 어떻게 대체합니까?
안티몬

17
@JacobB List 이해는 Python이 발명되기 약 15 년 전과 Python이 기능을 구현하기 25 년 전에 기능적 언어로 제공되었습니다. 파이썬이 그들의 확산에 영향을 미쳤다는 생각, 또는 fp가 파이썬으로부터 이것을 배웠거나 심지어 fp 세계에서 인기가 파이썬 구현 이후에 있다는 아이디어는 단순히 잘못되었습니다. 파이썬의 구현은 Haskell에서 직접 가져 왔습니다. 어쩌면 나는 당신을 오해했고 그것이 당신이 의미하는 바는 아니지만, "기능적인 사람들이 놀라운 목록 이해력으로 깨어나 기 시작 했다 "는 것에 당황하게됩니다 .
itsbruce

23

필자는 파이썬을 "기능적"이라고 부르지 않지만 파이썬으로 프로그램 할 때마다 코드는 거의 순전히 기능적으로 끝납니다.

틀림없이 그것은 목록 이해력이 매우 뛰어 나기 때문입니다. 따라서 필연적으로 파이썬을 함수형 프로그래밍 언어로 제안하지는 않지만 파이썬을 사용하는 사람에게는 함수형 프로그래밍을 제안합니다.


17

SO에 대한 "기능적" Python 질문 에 대한 답변에서 가져온 코드 조각으로 시연하겠습니다.

파이썬 :

def grandKids(generation, kidsFunc, val):
  layer = [val]
  for i in xrange(generation):
    layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
  return layer

하스켈 :

grandKids generation kidsFunc val =
  iterate (concatMap kidsFunc) [val] !! generation

여기에 가장 큰 차이점은 하스켈의 표준 라이브러리는 함수형 프로그래밍에 대한 유용한 기능을 가지고 있다는 것입니다 :이 경우 iterate, concat(!!)


7
다음 grandKids()은 제너레이터 표현식이있는 body를 한 줄로 대체 한 것입니다 return reduce(lambda a, v: concat((x for x in kidsFunc(v)) for v in a), xrange(generation), [val]).
Lloeki

6
그리고 여기에도 필요하지 않은 것이 concat있습니다 :return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val])
Lloeki

9
@Lloeki : 반복은 코드를 크게 단순화하고 (kidsFunc (v)의 x에 대한 v의 x는 concatMap (kidsFunc))보다 훨씬 명확합니다. 파이썬에는 고차원의 내장 기능이 없기 때문에 하스켈에 비해 동등한 코드를 암호화하고 자세하게 만듭니다.
Phob

2
concat은 다음으로 대체 될 수 있습니다itertools.chain.from_iterable
Antimony

@Antimony : 알아두면 좋습니다. thx
yairchu

14

이 질문 (및 답변)에 정말로 중요한 한 가지는 다음과 같습니다. 지옥은 기능 프로그래밍이란 무엇이며, 가장 중요한 속성은 무엇입니까? 나는 그것에 대한 나의 견해를 주려고 노력할 것이다.

함수형 프로그래밍은 화이트 보드에 수학을 쓰는 것과 비슷합니다. 화이트 보드에 방정식을 쓸 때 실행 순서를 생각하지 않습니다. (일반적으로) 돌연변이가 없습니다. 당신은 다음날 다시 와서 그것을 보지 않고 계산을 다시 할 때 다른 결과를 얻습니다 (또는 신선한 커피를 마셨다면 :). 기본적으로 칠판에있는 것이 있고, 글을 적을 때 이미 답이 있었지만 아직 그 내용을 깨닫지 못했습니다.

함수형 프로그래밍은 이와 매우 비슷합니다. 당신은 사물을 바꾸지 않고 단지 방정식을 평가하고 (이 경우 "프로그램") 답이 무엇인지 알아냅니다. 프로그램은 여전히 ​​수정되지 않은 상태입니다. 데이터와 동일합니다.

다음은 함수형 프로그래밍의 가장 중요한 기능으로 다음과 같이 평가합니다. a) 참조 투명성-다른 시간과 장소에서 동일한 문장을 평가하지만 동일한 변수 값을 사용하더라도 여전히 동일한 의미를 갖습니다. b) 부작용 없음-화이트 보드를 얼마나 오래 응시하더라도 다른 사람이 다른 화이트 보드를보고있는 방정식은 우연히 변경되지 않습니다. c) 함수도 값이다. 다른 변수와 함께 전달되거나 다른 변수에 적용될 수 있습니다. d) 함수 구성, h = g · f를 수행 할 수 있으므로 g (f (..))를 호출하는 것과 동일한 새 함수 h (..)를 정의 할 수 있습니다.

이 목록은 우선 순위에 따라 참조 투명성이 가장 중요하며 부작용이 없습니다.

이제 파이썬을 통해 언어와 라이브러리가 이러한 측면을 얼마나 잘 지원하고 보장하는지 확인하면 자신의 질문에 대한 답을 얻을 수 있습니다.


2
함수는 파이썬에서 일류입니다.
Carl Smith

@CarlSmith 그중 하나이지만 파이썬에는없는 3/4를 남깁니다. :-\
arya

1
나는 파이썬이 함수형 프로그래밍에 좋은 언어라고 생각하지 않습니다. 나는 그 의견의 의미가 정직하다는 것을 확신하지 못한다. 답과 관련이없는 것 같습니다. 나는 그것을 삭제하지만 귀하의 의견은 문맥에 맞지 않을 것입니다.
Carl Smith

1
참조 투명성과 불변성은 실제로 언어 기능이 아닙니다. 그렇습니다. 일부 언어 (Haskell)는 이들 언어를 강조하여 사용하기 어렵지만 본질적으로 모든 언어에서 참조 적으로 투명한 기능이나 불변의 객체를 만들 수 있습니다. 표준 라이브러리를 해결하기 만하면 종종 위반합니다.
Kevin

또한 파이썬은 커리와 컴포지션을 모두 지원하지만 언어 수준은 아니지만 표준 라이브러리에 있습니다.
Kevin

10

파이썬은 거의 기능적인 언어입니다. "기능적 라이트"입니다.

추가 기능이 있으므로 일부에 충분하지 않습니다.

또한 일부 기능이 없기 때문에 일부 기능으로는 충분하지 않습니다.

누락 된 기능은 비교적 작성하기 쉽습니다. 같은 게시물 확인 파이썬에서 FP에 있습니다.


2
대부분이 게시물에 동의합니다. 그러나 파이썬이 기능적인 언어라는 말에는 동의하지 않습니다. 명령형 프로그래밍을 장려하고 언급 한 "추가 기능"을 사용하는 것은 어렵습니다. 다른 포스트에서했던 것처럼 파이썬을 "기능적 라이트"라고 말하는 것이 가장 좋습니다. :-)
Jason Baker

8
-1 죄송합니다. 그냥 아니에요 기능적 언어는 공식 추론을 용이하게하는 구문을 제공합니다 : 유도 (ML), 방정식 (Haskell). 클로저 및 익명 함수만으로 전략 패턴의 구문 설탕 일뿐입니다.
pyon December

8

위에서 언급되지 않은 또 다른 이유는 내장 유형의 많은 내장 함수 및 메소드가 오브젝트를 수정하지만 수정 된 오브젝트를 리턴하지 않기 때문입니다. 수정 된 객체가 반환되면 기능 코드가 더 깨끗하고 간결 해집니다. 예를 들어 some_list.append (some_object)가 some_object가 추가 된 some_list를 반환 한 경우


4

다른 답변 외에도 Python 및 대부분의 다른 다중 패러다임 언어가 실제 기능 프로그래밍에 적합하지 않은 이유는 컴파일러 / 가상 머신 / 런타임이 기능 최적화를 지원하지 않기 때문입니다. 이러한 종류의 최적화는 컴파일러가 수학 규칙을 이해함으로써 달성됩니다. 예를 들어, 많은 프로그래밍 언어가 map함수 또는 메소드를 지원합니다 . 이것은 함수를 하나의 인수로 사용하고 iterable을 두 번째 인수로 사용하여 해당 함수를 iterable의 각 요소에 적용하는 상당히 표준적인 함수입니다.

어쨌든 그것은와 map( foo() , x ) * map( foo(), y )동일 하다는 것이 밝혀졌습니다 map( foo(), x * y ). 전자는 후자가 하나를 수행하는 두 개의 사본을 수행하기 때문에 실제로는 전자보다 빠릅니다.

더 나은 기능적 언어는 이러한 수학 기반 관계를 인식하고 자동으로 최적화를 수행합니다. 기능적 패러다임 전용 언어는 최적화되지 않을 것입니다.


map( foo() , x ) * map( foo(), y ) == map( foo(), x * y )모든 기능에 적용되는 것은 아닙니다. 예를 들어, foo미분을 계산할 때를 고려하십시오 .
Eli Korvigo

1
나는 그가 +대신 의미 를 생각 *합니다.
user1747134

foo ()가 선형이라고 가정합니까?
Juan Isaza

해당 속성은 foo (x) = x + 1에 해당되지 않습니다. 처럼 (x + 1) * (y + 1)! = x * y + 1
Juan Isaza
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.