엘릭서가 함수형 언어이기 때문에, 함수형 프로그래밍의 동작에 대해 익숙해지는 것이 좋습니다. 이전에 자바스크립트와 C#의 기능을 함수형으로 사용한 적은 있지만, 함수형 언어는 이번이 처음입니다. 그래서 저는 여기에 제가 아는 것들을 쓰겠지만 함수형 프로그래밍에는 그보다 훨씬 많은 것이 있을 것입니다.
저는 여러분이 엘릭서를 더 잘 이해하도록 제 관점에서 함수형 프로그래밍의 본질에 대한 최소한의 이해를 시켜드리고 싶습니다. 저는 우리가 진행하면서 함수형 프로그래밍의 본질에 대해 더 많이 배울 것이라고 확신합니다.
객체 지향 언어에서 데이터는 일반적으로 그것을 작동하는 함수와 결합되어 있습니다. 함수형 언어에서는 데이터와 함수는 엄격하게 분리되어 있습니다. 함수는 자체적으로 동작하지만, 관련된 함수들은 종종 모듈로 그룹화됩니다. 그리고 함수는 파라미터로 데이터를 받고 호출자에게 데이터를 반환합니다. 함수는 데이터를 변환하는 것으로 볼 수 있습니다.
사이드 이펙트란 어떤 함수가 그 함수 밖의 다른 부분에 영향을 미치는 것을 말합니다. 사이드 이펙트가 있는 함수는 전달된 것이 아닌 공유 데이터를 변경하는 것이며, 객체 지향 코드에서는 이것이 일반적입니다. 또한 사이드 이펙트가 있는 함수는 입력 데이터 가져오기, 출력 데이터 내보내기, 네트워크로 데이터 전송하기, 화면에 그리기 등의 환경에 영향을 끼칠 수 있습니다. 이것들은 모두 함수의 경계를 넘어선 효과들입니다.
사이드 이펙트가 없는 함수는 매개 변수를 가지고 그 데이터를 기반으로 연산을 수행하여 값을 반환합니다. 이러한 함수를 순수 함수라고 하며 완전히 독립적으로 존재할 수 있습니다. 순수 함수는 함수형 프로그래밍에서 이상적입니다. 여러분의 코드를 훨씬 더 이해하기 쉽게 만들고 특정 유형의 버그(이 데이터가 어떻게 그리고 어디서 수정되었는지)를 피할 뿐만 아니라, 함수를 테스트하기 쉽게 만들어 줍니다. 함수에서 오직 입력 파라미터에 기반하여 값이 반환되는 경우가 환경이 어떤 양항을 미치는지 알아내야 하는 경우보다 테스트가 훨씬 간단해질 것입니다.
현재 명백하게 사이드 이펙트가 없는 프로그램은 쓸모가 없을 것입니다. 프로그램은 다른 곳에서 온 입력을 읽고, 화면에 그리고, 다른 프로그램과 통신하고, 일반적으론 그들의 환경과 상호작용하는 것이 필요합니다. 그래서 여러분은 적어도 약간의 사이드 이펙트가 있는 함수를 가지고 있어야 합니다. 함수형 프로그래밍의 관례는 이를 인식하고 있으며, 사이드 이펙트에만 전념하는 특별한 함수로 두어 격리하는 것이 최선입니다.
값을 연산하고 화면에 써야 하나요? 가능합니다. 그러나 그것을 같은 함수 안에서 하지는 마십시오. 순수 함수는 입력값을 받아서 계산하고 결과를 출력합니다. 그리고 다른 함수는 데이터 일부를 가져와서 화면에 표시하는 것만 합니다. 이러한 사이드 이펙트를 격리하는 것은 함수형 코드를 테스트하기 쉽고 쉽게 읽고 유지보수 할 수 있도록 도와줍니다. 화면에 기록된 함숫값을 추측할 수 없습니다. 그것은 모두 그것을 담당하는 함수에서 이뤄집니다.
함수형 프로그래밍은 언어에서 일급 1급 시민인 함수가 필요합니다. 함수는 다른 데이터처럼 전달될 수 있어야 합니다. 그것은 변수에 할당하고, 다른 함수에 파라미터로 전달하며, 함수에서 반환 값으로 전달될 수 있어야 합니다.
자바스크립트와 같은 일부 명령형 언어들에서는 이것이 가능합니다. 자바스크립트와 같은 언어에서 함수형 프로그래밍을 하는 것은 가능하지만, 언어가 그 개념을 가지고 만들어지지는 않았습니다. C나 C++, 그리고 초기 버전의 자바와 초기 버전의 C#과 같은 언어에서는 불가능합니다. 함수를 단순히 그렇게 사용할 수 없습니다.
함수형 프로그래밍에서는 작은 함수를 강조하여 함수를 이해하기 쉽고 테스트하기 쉽게 만듭니다. 이러한 함수들은 다양한 방법으로 결합하여 다른 함수를 만들고, 종종(항상 그렇지는 않지만) 다양한 상황에서 재사용될 수 있습니다. 유닉스에 익숙하신 분들은 이것과 좀 더 복잡한 것을 만들기 위해 다양한 방식으로 결합할 수 있는 작고 전문적인 도구를 많이 갖도록 하는 유닉스의 철학의 유사성에 주목할 것입니다.
함수형 언어에서는 이전 변환 함수의 결과가 다음 함수로 전달되는 데이터 변환 파이프라인을 설정하는 것이 일반적입니다. 여러 개의 단순한 함수들에 적용하면 복잡한 함수와 같은 것을 수행할 수 있고, 그것들은 훨씬 테스트하기 쉽고 이해하기 쉽습니다.
이상적으로 함수형 언어에서 데이터는 불변형입니다. 이것은 많은 프로그래밍 문제를 해결합니다: 동시성 프로그래밍에서 가변 상태 공유와 관련된 문제뿐만 아니라 데이터가 예기치 않게 수정되고 어떻게 이 상태가 되었는지 코드를 추적해야 하는 문제까지도 방지합니다. 가변 상태를 공유하는 코드를 작성하고 그로 인해 발생하는 문제를 처리하기 전까지는 불변 데이터의 이점을 진정으로 이해할 수 없을 것입니다.
가변 데이터를 공유하는 것은 일반적으로 한 번에 하나의 스레드에 대한 접근을 제어하도록 락을 걸게 되며, 다른 스레드가 끝나기를 기다릴 때 성능 문제가 발생할 수 있습니다. 2개 혹은 3개의 스레드에서는 괜찮지만, 수백 개의 스레드로 늘어나면 성능에 문제가 생기고 확장성이 제한됩니다. 동시성과 확장성에 최적화된 엘릭서는 모든 데이터를 불변형으로 하여 이 문제를 완전히 회피합니다.
함수형 언어는 데이터를 수정하지 않습니다. 새로운 데이터 셋으로 변환합니다. 함수형 언어에서 많은 함수는 데이터를 변환을 위해 사용됩니다. 이것은 불편 데이터의 개념과 딱 맞습니다.
불변의 이점은 프로그래밍을 단순하게 하고 에러 발생률을 줄이는 것입니다. 단점은 가변 데이터를 변경하는 것보다 덜 효율적인 경향이 있다는 것입니다. 불변 데이터를 수정하는 것은 종종 원본 데이터의 일부 복사를 포함하지만, 컴파일러가 데이터가 불변이라는 것을 안다면 몇 가지 놀라운 최적화가 일어날 수 있습니다.
데이터는 서로 다른 데이터 구조로부터 공유될 수 있습니다. 데이터는 수정되지 않으므로 복사하지 않고도 재사용 할 수 있습니다. 이런 데이터 구조 중 하나는 "트라이(trie)"(때로는 "tree"로 발음되기도 하고 "try"로 발음되기도 함)입니다. 어레이와 같은 큰 불변 데이터 구조를 최소한의 복사만으로 변경할 수 있습니다. 변경이 되고 나면 데이터 대부분은 두 데이터 구조로부터 공유됩니다.
트라이(tries)와 불변 데이터 구조에 관한 매우 흥미로운 설명은 JSConf에서 Anjana Vakil의 불변 데이터 구조 프레젠테이션 비디오를 확인하십시오. 그것은 정말로 저를 깨닫게 해주었습니다. 트라이(tries)를 잘 설명하는 다른 재미있는 비디오들도 많이 있습니다.
함수형 언어는 이러한 종류의 최적화를 흥미로운 방식으로 사용하기 때문에 다른 데이터를 얻기 위해 불변 데이터 구조를 변경 하는 것이 훨씬 효율적입니다. 자바스크립트와 같이 함수형이 아닌 언어는 함수형 프로그래밍에 최적화된 불변 데이터 구조를 기본적으로 가지고 있지 않지만, 자바스크립트에서 불변 데이터 구조를 구현한 immutable.js와 같은 라이브러리를 사용하면 불변 데이터 구조를 사용할 수 있습니다.
불변 데이터 구조에 익숙하지 않은 사람에게는 엘릭서에서 불변 데이터 전체를 복사하는 것이 훨씬 더 효율적인 것으로 들릴 수 있겠지만, 결코 가변 데이터 구조를 수정하는 것만큼 효율적이지 않을 것입니다. 엘릭서는 확장 가능한 동시성을 가능하게 하도록 기꺼이 효율적인 페널티를 갖습니다. 엘릭서에선 특정 코드 일부의 작은 성능 문제가 발생하는 것이 스케일 업을 하는 것과 같은 전체 시스템에서의 주요 성능 문제가 발생하는 것보다 더 선호됩니다.
고차 함수는 함수를 파라미터로 받거나 함수를 리턴 할 수 있는 함수입니다. 고차 함수는 함수형 프로그래밍에서 매우 일반적입니다. 매우 일반적인 사용법은 변환 함수를 다른 함수로 전달하고 , 이 변환을 컬렉션의 모든 요소마다 적용하는 것입니다. 자바스크립트의 Array.map
함수나 C# 의 IEnumerable.Select
메서드는 집합의 모든 요소에 함수 파라미터를 적용하기 때문에 고차 함수의 예시 입니다.
함수형 언어와 절차형 언어(C와 파스칼 같은)는 모두 데이터와 함수를 분리하려는 경향이 있지만, 이 둘은 철학적으로 큰 차이가 있습니다. 절차형 언어에서 함수는 일반적으로 1급 객체가 아니고 절차형 프로그래밍은 훨씬 더 명령형 스타일을 가지고 있습니다. 함수형 프로그래밍은 좀 더 선언형입니다. 절차형 프로그래밍은 일을 처리하기 위해 어떻게 해야 하는지를 강조하고 함수형 프로그래밍은 일을 처리하기 위해 무엇을 해야 하는지를 강조합니다. 선언형의 함수형 사고방식은 아직 숙달되지 않았지만, 엘릭서를 통해 더 잘 파악하길 희망합니다.
절차형 언어는 일반적으로 불변 데이터, 고차 함수 및 쉬운 합성과 같은 기능들을 제공하지 않습니다. 함수형 언어는 함수 일관성(같은 입력값은 항상 같은 출력)과 사이드 이펙트가 없는 것을 강조합니다.
언어는 유연하게 할 수도 있긴 합니다만. C는 함수 포인터와 많은 특화된 라이브러리를 함수형 프로그래밍으로 하면 아마도 고통받을 것이고, 자바스크립트는 매우 유연해서 라이브러리의 도움을 받아 많은 것들을 할 수 있을 것입니다. 언어는 설계되지 않은 일을 하도록 변형 할 수 있지만, 설계된 대로 사용하는 것이 더 좋습니다.
함수형 언어는 함수형 프로그래밍을 지향하지만, 오용하는 것을 막지는 못할 것입니다. 명령형 프로그래머는 여전히 함수형 언어에서 명령형 스타일의 코드를 작성하고 언어가 의도한 대로 사용하지 않을 것으로 생각됩니다. 제가 이렇게 하게 될까 봐 우려되기 때문에, 엘릭서를 배우면서 함수형 스타일의 프로그래밍을 더 잘 배우려고 합니다.
이 특정한 문제에 대한 해답은 기존의 엘릭서 코드에 주의를 기울이고 연습하고 또 연습해야 합니다. 아무것도 하지 않고는 절대 엘릭서를 숙달할 수 없으므로 책을 읽고 비디오를 볼 것입니다. 엘릭서로 많은 프로그래밍을 할 것입니다.
저는 제가 함수형 프로그래밍을 완전히 숙달하기까지 갈 길이 멀다고 생각합니다. 이것은 다른 사고방식이고 제가 진행하면서 실수를 저지를 것 같습니다. 이전에 저에게 효과가 있었던 많은 익숙한 프로그래밍 패턴은 함수형 프로그래밍 환경에서는 쓸모가 없거나 오해의 소지가 있을 것입니다.