ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 함수형 프로그래밍이란 (2편 언어에서 조망)
    Humor 2016. 1. 23. 00:23

    어떤 프로그래밍 언어들이 함수형인가?

    Which Programming Languages Are Functional?


    작성일: 2015년 12월 29일

    29 Dec 2015


    이 글의 1부에서 나는, 학문적이거나 마케팅적인 관점을 떠나 평범한 프로그래머가 이해할 수 있도록 함수형 프로그래밍을 정의했다. 사실 그보다 더 중요한 것은 부작용(혹은 부대작용, side-effect)이 무엇인지 이해하고 그것이 통제를 벗어나기 전에 발견할 수 있게 한 것이다(적어도 그랬기를 바란다).

    In part one of this post, I defined functional programming not from an academic perspective, or a marketing one, but in a way that will make sense to a jobbing programmer. More importantly, I hope, I defined what side-effects are in a way that makes it easy for a jobbing programmer to spot them before they spiral out of control.


    이제, 현실 세계에서 함수형 프로그래밍 언어를 찾아 보자…

    Now, let's take a look at functional programming languages in the real world…


    프로그래밍 전반에 걸쳐…

    Pot Shots Across the Programming Landscape


    부작용을 발견할 수 있는 눈을 가졌으니 주어진 함수에 숨어있는 복잡성도 발견할 수 있게 됐다. 현실적인 FP정의를 알았으니, 그것을 기반으로 프로그래밍 세상 전방위에 걸쳐 새로 획득한 통찰을 발휘해보자.

    Armed with the ability to spot side-effects, we can now look at a given function and spot hidden complexity. And armed with some real-world definitions of FP, we can now survey the programming world and fire some new insights in practically every direction…


    함수형 프로그래밍은 …이 아니다

    Functional Programming is not…

    map이나 reduce가 아니다

    It's not map and reduce

    모든 함수형 언어에서 이 함수들을 보게 된다 할지라도 이것으로 인하여 어떤 언어가 함수형이 되는 것은 아니다. 시퀀스 자료를 처리하는 과정에서 부작용을 걷어내려고 노력하다보면 언제나 얻게되는 함수들일 뿐이다.

    Even though you'll see these functions in every functional language, it's not what makes the language functional. It's just something that crops up nearly every time you try to take the side-effects out of processing sequences of things.

    람다 함수가 아니다

    It's not lambda functions

    역시나 여러분이 보게 될 모든 FP 언어에는 일급 함수(first-class function)가 있을 것이다. 람다 함수 역시 부작용을 회피하기 위한 언어를 만들다보면 자연스럽게 얻어지는 것이다. FP를 가능하게 하는 것이지 핵심 요소는 아니다.

    Again, you'll probably see first-class functions in every FP language. But it's something that naturally emerges when you start building a language that avoids side-effects. It's an enabler, but not the root cause.

    타입에 관한 것이 아니다

    It's not types

    정적 타입 검사는 매우 유용한 도구이지만 FP의 전제 조건이 아니다. Lisp은 가장 오래된 함수형 프로그래밍 언어이자 가장 오래된 동적 언어이기도 하다.

    Static type checking is a very useful tool, but it's not a pre-requisite for FP. Lisp is the oldest functional programming language, and the oldest dynamic language.

    정적 타입이 매우 유용할 수는 있다. 하스켈은 타입 시스템을 사용하여 아름답게 부작용을 공격한 케이스다. 그러나 정적 타입이냐 아니냐가 함수형 언어이냐 아니냐를 가르지는 못한다.

    Static types can be very useful though. Haskell uses its type system beautifully in the attack on side-effects. But they aren't the ingredient that makes or breaks a functional language.

    큰 소리로 길게 말해보자. 함수형 프로그래밍은 부작용에 관한 것이다.

    Say it long, say it loud, functional programming is about side-effects.

    (물론 부원인도 포함한다)

    (And side-causes, of course).


    언어 차원에서 의미하는 바는 무엇인가?

    What Does This Mean For Languages?


    자바스크립트는 함수형 프로그래밍 언어가 아니다

    JavaScript is not a Functional Programming Language

    함수형 언어는 여러분이 부작용을 제거할 수 있는 곳에서는 제거를 돕고, 그럴수 없는 곳에서는 통제할 수 있게 도와준다. 자바스크립트는 이 기준을 만족하지 않는다. 사실 자바스크립트가 적극적으로 부작용을 장려하는 것은 쉽게 찾을 수 있다.

    Functional languages help you eliminate side-effects where you can, and control them where you can't. JavaScript doesn't meet this criteria. In fact, it's easy to spot places where JavaScript actively encourages side-effects.

    가장 쉽게 찾을 수 있는 것이 바로 this이다. this는 모든 함수의 숨겨진 입력이다. 특히 this가 마법처럼 보이는 까닭은 의미 변화가 자유롭기 때문이다. 심지어 전문가라고 할만한 자바스크립트 프로그래머들조차 this의 참조 대상을 추적하는데 어려움을 겪는다. 함수형 관점에서 보자면 어디서나 마법처럼 접근 가능하다는 사실이 설계 결함의 징후(design smell)이다.

    The easiest target is this. The hidden input that's in every function. What's particularly magical about this is how freely its meaning changes. Even expert JavaScript programmers have trouble keeping track of what this currently refers to. From a functional point of view, the fact that it's magically available at all is a design smell.

    여러분은 분명 FP 라이브러리(예를 들어 Immutable.js)를 로드할 수 있고 또 이를 통해 함수형 스타일로 프로그래밍 하기가 더 쉬워지기는 하겠지만 언어 자체의 본질은 바뀌지 않는다.

    While you can certainly load FP libraries (Immutable.js, for instance) into JavaScript, and that makes programming in a functional style easier, it doesn't change the nature of the language itself.

    (여러분이 만약 요즘 자바스크립트 진영에서 인기를 더해가는 함수형 라이브러리들을 좋아한다면 한번 상상해 보라. 언어 자체가 함수형 스타일을 지원한다면 얼마나 좋아질지를…)

    (By the way, if you like the functional libraries that are gaining popularity in JavaScript land, imagine how much you'd like a whole language that supported the functional style.)


    자바는 함수형 프로그래밍 언어가 아니다

    Java is not a Functional Programming Language

    자바는 확실히 함수형 언어가 아니다. 자바 1.8에서 람다가 추가되었다고 바뀌는 것은 없다. 자바는 함수형 프로그래밍과 정반대 지점에 있다. 자바의 핵심 설계 원칙에서 말하는 것이 바로 “코드는 지역화된 부작용들—즉 객체의 지역 상태를 변경하거나 지역 상태에 의존하는 메쏘드들—로 조직화되어야 한다”이다.

    Java is most definitely not a functional language. The addition of lambdas in Java 1.8 does nothing to change that. Java stands in stark opposition to functional programming. It's core design principal says that code should be organised as a series of localised side-effects - methods that depend on and change the local state of an object.

    사실, 자바는 함수형 프로그래밍에 적대적이다. 여러분이 자바 코드를 작성하면서 부작용 없게, 즉 로컬 객체 상태를 읽거나 변경하지 않게 작성한다면, 여러분은 “나쁜 프로그래머”라고 불리게 될 것이다. 자바는 원래 그런 식으로 작성하지 않기 때문이다. 여러분이 작성한 부작용 없는 코드는 static 키워드로 점철될테고 여러분은 잔뜩 화가난 동료들에 의해 자바 동네에서 쫓겨날 것이다.

    In fact, Java is hostile to functional programming. If you write Java code that has no side-effects, that doesn't read or change the local object's state, you'll be called a Bad Programmer. That's not how Java is written. Your side-effect free code will be peppered with static keywords, and they'll frown and drive you out of town.

    자바가 틀렸다는 말을 하려는게 아니다. (음, 좋다. 그걸 부정하지는 않겠다) 요지는 부작용에 대해 완전히 다른 관점을 가지고 있다는 점이다. 자바는 부작용을 국소화하는 것을 좋은 코드의 초석이라고 보며, FP는 부작용을 악으로 간주한다.

    I'm not saying Java is wrong. (Well, okay, I am.) But the point is it takes a completely different view of side-effects. Java thinks that localised side-effects are cornerstone of good code; FP thinks they're the devil.

    여러분은 조금 다른 각도에서 볼 수도 있다. 자바나 FP나 부작용의 문제에 대한 응답이라고 볼 수 있다. 두 가지 모델 모두 부작용을 문제라고 인식하는 것은 같지만 반응이 다를 뿐이다. OO의 대답은 “부작용을 ‘객체’라는 경계에 가두어라”이고, 반면 FP의 대답은 “부작용을 제거하라”이다. 안타깝게도 사실상 자바는 부작용을 캡슐화하려는 시도를 전혀 하지 않으며 오히려 그것을 필수화한다. 상태를 가진 객체라는 형태로 부작용을 만들지 않는다면 여러분은 “나쁜 자바 프로그래머”일 뿐이다. 실제로 static을 너무 자주 사용한다고 해고되는 경우도 있다.

    You could look at that from a slightly different angle. You could see both Java and FP as responses to the problem of side-effects. Both models recognise side-effects as a problem, and respond differently. OO's answer is, "contain them within boundaries called 'objects'," whereas FP's answer is, "eliminate them". Unfortunately, in practice Java doesn't just try to encapsulate side-effects; it mandates them. If you're not creating side-effects, in the form of stateful objects, then you're a Bad Java Programmer. People actually get fired for writing static too often.


    스칼라는 큰 짐을 지고 있다

    Scala Has a Big Task on its Hands

    이러한 관점에서 보자면 스칼라는 매우 도전적인 제안이다. 스칼라의 목표가 OO와 FP라는 두 세상을 통합하는 것이라면, 부작용이라는 렌즈로 들여다 봤을 때 스칼라가 “부작용 필수”와 “부작용 금지” 사이의 격차를 해소하려는 것이라고 볼 수 있다.(1) 이 둘은 이렇게나 정반대의 관점을 가지기 때문에 나는 이 둘의 조화가 가능할 것이라고 보지 않는다. 객체에 map 메쏘드를 추가한다고 두 세상이 통합되지는 않는다. 부작용에 관한 상반된 두 입장 사이의 충돌을 해소하려면 더 깊은 고민이 필요하다.

    Seen in this light, Scala is a very challenging proposition. If its goal is to unify the two worlds of OO and FP, then through the lens of side-effects we see it as trying to bridge the gap between "Side-Effects Mandatory" and "Side-Effects Forbidden(1)". They're such opposite views that I'm not sure they can be reconciled. You certainly can't unify the two just by making objects support the map function. You'll need to go deeper and reconcile the conflict between the two opposing stances on side-effects.

    스칼라가 이런 화해에 성공적인지에 대한 판단은 여러분에게 맡기겠다. 다만 내가 만약 스칼라의 마케팅을 담당한다면 스칼라를 이렇게 홍보하겠다. 자바라는 부작용 필수 세상을 떠나 FP라는 순수한 세상으로의 점진적 이동을 도와준다고. 이 두 세상을 통합하는 것이 아니라 이어주는 다리 역할을 할 수 있다고. 실제로, 많은 사람들이 그런 식으로 보고 있다.

    I'll leave you to judge if Scala succeeds in such a reconciliation. But if I were in charge of Scala's marketing I'd sell it as a gradual move away from the side-effecting world of Java, to the pure world of FP. Instead of unifying them, it could be a bridge away. Indeed, many people see it that way in practice.


    클로져

    Clojure

    클로져는 부작용에 대해 흥미로운 입장을 취한다. 클로져를 만든 리치 히키(Rich Hickey)는 클로져가 “80% 함수형”이라고 했다. 나는 그 이유를 설명할 수 있을 것 같다. 처음부터 클로져는 ‘시간’이라고 하는 한가지 특정 부작용을 잘 처리하도록 설계되었다.

    Clojure takes an interesting stance on side-effects. Its creator, Rich Hickey, has said that Clojure is about "80% functional". I think I can clarify why that is. From the outset, Clojure was designed to deal with one specific kind of side-effect: Time.

    이를 설명하기 위해 먼저 자바 관련 농담을 하나 살펴보자.

    To illustrate this, here's a Java joke for you:

    물론 훌륭한 농담은 아니다. 그러나 요점은, 자바 세상에서 값은 그대로 유지되지 않는다. 합당하게 5라고 볼 수 있는 어떤 값이 있는데, 다른 함수를 하나 호출한 다음에는 5가 아닐 수 있다는 것이다. 수학에서 5는 절대 바뀌지 않는다. 새로운 값을 반환하는 함수를 부를 수는 있어도 5라는 값 자체가 바뀌지는 않는다. 자바는 값이 시간에 따라 바뀌긴 하지만 그 변화가 객체 경계로 감싸져 있다면 문제 없다고 말한다.

    Okay, it's not a great joke. But the point is, in Javaland, values don't stay still. We might legitimately take something that represents a five, call a function, and find that it's no longer a five. Mathematics says that five never changes - we can call a function that gives us a new value, but we can never affect the nature of five itself. Java says values change all the time, and as long as they're wrapped in object boundaries that's okay.

    정수 값을 봤을 때는 대수롭지 않게 보일 수 있다. 하지만 더 큰 값이라면 효과가 증폭된다. 1부에서 예로 다루었던 InboxQueue를 기억하는가? InboxQueue의 상태는 시간이 지남에 따라 변하는 값이다. 우리는 시간(Time)을 InboxQueue의 의미에 대한 부원인(side-cause)이라고 볼 수 있다.

    The integer case may seem trivial, but the effect is amplified when we look at larger values. Remember InboxQueue from part 1? The state of InboxQueue is a value that changes over time. We can say that Time is a side-cause to the meaning of InboxQueue.

    클로져는 시간이라는 부원인에 매우 집착한다. 시간의 숨겨진 효과 때문에 우리가 저장한 값에 의존할 수 없게 되고, 저장한 값에 의존할 수 없으면 함수의 입력값에도 기댈수 없게 되며, 따라서 우리는 어떠한 것에도 그것이 예상가능하게 혹은 반복적으로 동작할 것이라고 의존할 수 없게 된다는 것이 바로 리치 히키의 통찰이다.(2) 값 조차도 부작용을 가진다면 모든 것이 부작용을 가지게 된다. 값이 순수하지 않으면 우리 프로그램에서 어떤 것도 순수할 수 없다.

    Clojure focuses ferociously on the side-cause of Time. Rich Hickey's insight(2) is that the hidden effect of time means we can't rely on values to stay put; and if we can't rely on that, we can't rely on our functions' inputs, and so we can't rely on anything to behave predictably or repeatably. If even values have side-effects, then everything has side-effects. If values aren't pure, nothing in our programs can be pure.

    그래서 클로져는 시간에 칼을 들이댄다. 클로져의 모든 값은 기본적으로 불변이다(시간이 지남에 따라 변하지 않는다). 변하는 값이 필요한 경우를 위해 클로져는 변하지 않는 값의 wrapper를 제공한다. 이러한 래퍼는 무거운 제약사항을 가진다.

    So Clojure takes a sword to time. All its values are immutable (unchanging over time) by default. If you need a changing value, Clojure provides wrappers around unchanging values, and those wrappers are subject to heavy constraints:

    시간에 관한 한, 클로져는 함수형 프로그래밍 언어의 좋은 예이다. 언어 차원에서 시간 부작용에 매우 적대적이다. 클로져는 기본적으로 제거할 수 있는 시간 부작용을 제거하며, 여러분이 필요하다고 여기는 부작용에 대해서는 그것이 여러분의 나머지 프로그램으로 번져나가지 못하다록 단단히 통제할 수 있게 도와준다.

    With respect to time, Clojure is a great example of a functional programming language. The language is deeply hostile to the side-effect of time. It eliminates it wherever it can, by default, and where you feel you must have the side-effect, it helps you tightly control it so it doesn't spill into the rest of your program.


    하스켈

    Haskell

    클로져가 시간에 대해 적대적이었다면 하스켈은 그냥 전부 적대적이다. 하스켈은 부작용을 정말 싫어하며 그것을 통제하는데 엄청난 노력를 쏟고 있다.

    If Clojure is hostile to time, Haskell is just plain hostile. Haskell really hates side-effects, and puts a large amount of effort into controlling them.

    하스켈이 부작용과 싸우는 흥미로운 방법 중 하나는 타입이다. 하스켈은 모든 부작용을 타입 시스템으로 밀어 올린다. 예를 들어, getPerson 함수가 있다고 가정해보자. 하스켈로는 아마 이렇게 생겼을 것이다.

    One of the interesting ways Haskell fights side-effects is with types. It pushes all side-effects up into the type-system. For example, imagine you've got a getPerson function. In Haskell it might look like:

    “UUID를 받고 Database 컨텍스트에서 Person을 반환한다” 정도로 읽을 수 있다. 여기서 흥미로운 건, 여러분이 하스켈 함수의 타입 시그너쳐만 보고서도 어떤 부작용이 관련되는지 확실히 알 수 있다는 점이다. 그리고 어떤 부작용이 관련되지 않는지도. “이 함수는 타입에 해당 부작용이 선언되지 않았기 때문에 파일 시스템을 접근하지 않는다”라고 보장할 수도 있다. 엄격한 통제다.(3)

    You can read that as, "takes a UUID and returns a Person in the context of a Database". This is interesting - you can look at the type signature of a Haskell function and know for certain which side-effects are involved. And which aren't. You can also make guarantees like, "this function won't access the filesystem, because it's not declared that kind of side-effect." Tight control(3).

    마찬가지로 중요한 것은, 여러분이 다음처럼 생긴 함수를 본다면…

    Equally important, you can look at a function like:

    … 이 함수가 Person을 받아서 String을 반환하다는 것을 알 수 있다. 다른 건 전혀 없다. 만일 이 함수에 부작용이 있다면 타입 시그너쳐에 분명히 표시되어 여러분이 알 수 있기 때문이다.

    …and know that this just takes a Person and returns a String. Nothing else, because if there were side-effects you'd see them locked into the type signature.

    하지만 아마도 무엇보다도 흥미로운 것은 다음 예일 것이다.

    But perhaps most interesting of all, is this example:

    시그너쳐는 formatName 함수가 데이터베이스 관련 부작용을 포함한다는 걸 알려준다. 이게 무슨? 왜 formatName 같은 함수가 데이터베이스를 필요로 하는거지? 그건 formatName을 테스트하려면 데이터베이스를 셋업하거나 mock을 사용해야 한다는 의미이기도 하다. 이건 정말 이상하다.

    The signature tells us that this version of formatName involves database-related side-effects. What the hell? Why does formatName need the database? You mean I'm going to need to set-up and mock-out a database just to test a name-formatter? That's really weird.

    함수의 시그너쳐만 보고서도 나는 설계 문제점을 볼 수 있다. 코드를 들여다볼 필요도 없이 나는 개요만 보고서 코드 냄새를 맡을 수 있다. 이건 마법과도 같다.

    Just by looking at this function signature, I can see something's wrong with the design. I don't need to look at the code, I can smell a rat just from the overview. That's magic.

    자바의 시그너쳐도 간단히 비교해보자.

    Let's just briefly compare that with the Java signature:

    하스켈 버전의 두 시그너쳐 중에서 어떤 것이 이것과 동등한가? 함수의 몸체를 들여다보지 않고서 여러분은 알 길이 없다. 순수 버전일 수도 있고, 데이터베이스를 접근할 수도 있다. 아니면 파일시스템을 모두 지워버리고 “팀장, 엿먹어라!”를 반환할 수도 있다. 실제 어떤 일이 일어날지 타입 시그너쳐로 알 수 있는 것이 거의 없고, 함수의 표면이 무엇인지도 알 수 없다.

    Which Haskell-version is that equivalent to? Without seeing the body of the function, you have no way of knowing. It may be the pure version, it may access the database. Or it may delete the filesystem and return, ="screw you boss!"=. The type signature tells you very little about what's going on, or what the surface area of the function is.

    대조적으로, 하스켈의 타입 시그너쳐는 설계에 관하여 상당히 많은 내용을 말해준다. 그리고 컴파일러에 의해 체크되므로 여러분은 그것이 사실임을 알고 있다. 타입 시그너쳐가 훌륭한 아키텍쳐 도구라는 의미이다. 설계 상의 문제를 매우 높은 수준에서 표면에 드러낸다. 코딩 패턴도 마찬가지로 표면에 드러난다. 나는 이 글에서 ‘Functor(펑터, 함자)’와 ‘Monad(모나드)’같은 말을 사용하지 않을 것이다. 하지만 고수준의 소프트웨어 패턴은 고수준의 분석으로 시작되며, 고수준의 분석은 여러분이 고수준의 표기법을 사용하면 훨씬 더 쉽다는 점을 말하고 싶다.(4)

    Haskell's type signatures, in contrast, tell you a great deal about the design. And because they're checked by the compiler, they tell you things you know to be true. And that means they make great architectural tools. They surface design-smells at a very high level, And they also surface patterns of coding too. I'm going to keep the words 'functor' and 'monad' out of this post, but I will say that high-level software patterns begin with high-level analysis, and high-level analysis is made much easier when you have a high-level notation(4).


    Perl

    부작용에 관한 논의라면 펄 얘기를 안하고 지날 수 없다. 펄에는 마법과 같은 인수 $_가 있는데, 이는 “이전 호출의 반환 값”을 의미한다.(5) 핵심 라이브러리 함수들 중 많은 것들이 이 값을 사용하거나 혹은 변경한다. 묵시적으로. 내가 아는 한 이 기능으로 인해 펄은 단 하나의 전역 부작용이 핵심 기능으로 간주되는 유일한 언어이다.

    Perl deserves a mention here in any discussion of side-effects. It has a magic argument, $_, which means something like, "the return value of the previous call(5)." It gets used and/or changed by many of the core library functions, implicitly. As far as I know this gives Perl the distinction of being the only language where one global side-effect is considered a core feature.


    파이썬

    Python

    자바에서의 근본적인 부작용 패턴을 잠깐 살펴보자.

    Let's take a quick look at a fundamental side-effecting pattern in Java:

    이 함수를 어떻게 순수하게 만들 수 있을까? this가 숨겨진 입력이므로 인자로 끌어올리기만 하면 된다.

    How would we purify this call? Well, this is the hidden input, so all we have to do is lift it up to an argument:

    이제 getName은 순수 함수이다. 파이썬은 기본적으로 이 두 번째 패턴을 채택하고 있음을 주목하자. 파이썬에서, 모든 객체 메소드는 this를 첫번째 인자로 가진다. 다만 그것을 self라고 부를 뿐이다.

    Now getName is a pure function. It's noteworthy that Python adopts this second pattern by default. In python, all object methods take this as the first argument, except by convention they call it self:

    분명히 명시적인 것이 묵시적인 것보다 낫다.

    Explicit is better than implicit indeed.


    Mocking

    Mocking

    Mock 프레임워크는 보통 두 가지 일을 한다.

    Mocking frameworks usually do two things.

    하나는 입력으로 사용할 값 객체를 설정하는 것을 돕는 일이다. 언어가 복잡한 값을 설정하기 어렵게 만들 수록 Mock 프레임워크가 더 유용하게 느껴질 것이다. 하지만 이 얘기는 접어두고..

    The first is they help you set up value objects to act as inputs. The harder your language makes it to set up complex values, the more useful you'll find this. But that's an aside.

    이 논의에서는 두 번째가 흥미롭다. Mock 프레임워크는 테스트 대상 함수에 대해 부원인(side-cause)을 올바르게 설정하고, 테스트가 실행된 다음 부작용(side-effect)을 제대로 추적하도록 돕는다.

    The second is more interesting in this discussion - they help you set up the right side-causes to the function under test, and track that the right side-effects have occurred after the test.

    부작용의 렌즈로 보자면 mock은 여러분의 코드가 순수하지 않음을 보여주는 표시이며, 함수형 프로그래머의 눈에는 무언가 잘못되었다는 증명인 셈이다. 맞닥뜨린 빙산을 확인하기 쉽게 도와주는 라이브러리를 다운로드하는 대신 빙산을 우회하여 항해해야 한다.

    Seen through the lens of side-effects, mocks are a flag that your code is impure, and in the functional programmer's eye, proof that something is wrong. Instead of downloading a library to help us check the iceberg is intact, we should be sailing around it.

    한번은 하드코어 TDD/자바 개발자가 내게 클로져에서 mocking을 어떻게 하느냐고 물어온 적이 있다. 그 대답은 우리는 일반적으로 mocking하지 않는다 이다. 우리는 대개 그것을 리팩토링이 필요한 신호로 본다.

    A hardcore TDD/Java guy once asked me how you do mocking in Clojure. The answer is, we usually don't. We usually see it as a sign we need to refactor our code.


    디자인 냄새 (또는 무의 향기)

    Design Smells (or The Scent Of Nothingness)


    부작용에 관한 I-Spy 책이 있다면, 가장 발견하기 쉬운 두 가지 타겟이 바로 인자 없는 함수와 반환값 없는 함수일 것이다.

    If there were an I-Spy book of side-effects, the two easiest targets to spot would be functions that take no arguments, and functions that return no value.


    인자가 없으면 부원인 신호

    No Arguments Signal Side-Causes

    인자가 없는 함수는 둘 중 하나다. 이 함수는 항상 같은 값을 반환하거나 다른 곳으로부터 입력을 취한다(즉 부원인이 있다).

    Whenever you see a function with no arguments, one of two things are true: Either it always returns exactly the same value, or it's getting its inputs from elsewhere (ie. it has side-causes).

    예를 들면, 다음 함수는 항상 같은 값을 반환하거나 아니면 부원인을 가진다.

    For example, this function must always, always return the same integer (or it has side-causes):

    반환값이 없으면 부작용 신호

    No Return Value Signals Side-Effects

    반환값이 없는 함수는 부작용이 있거나 호출해봤자 아무 의미 없는 함수이다.

    And whenever you see a function with no return value, then either it has side-effects, or there was no point calling it:

    함수 시그너쳐만 보자면 절대 이 함수를 호출할 이유가 없다. 이 함수를 불러봤자 아무 값도 얻을 수 없다. 이 함수를 호출할 유일한 이유는 이 함수가 조용히 발생시키게 될 마법과 같은 부작용 뿐이다.

    According to that function signature, there is absolutely no reason to call this function. It doesn't give you anything. The only reason to call it is for the magical side-effects it promises it will silently cause.


    요약 / 결론(?)

    Summary / Conclusion-y Thing


    부작용을 실제적이고 직관적으로 인식하는 것은 앞으로 여러분이 코드를 바라보는 시각을 바꿀 것이다. 개별 함수를 보는 것에서부터 전체 시스템 아키텍쳐를 보는 눈까지, 모든 것을 바꿀 것이다. 여러분이 프로그래밍 언어나 도구, 기술을 바라보는 방식을 바꿀 것이다. 그것은 모든 것을 바꿔놓는다. 오늘 당장 부작용을 죽이러 가자!

    A real, intuitive awareness of side-effects will change the way you look at coding. It will change everything from how you look at individual functions, right up to overall systems-architecture. It will change the way you look at programming languages, tools and techniques. It changes everything. Go kill a side-effect today…


    각주

    Footnotes:

    1

    Java와 OO를 하나처럼 이야기하는데, 맞다. Scala 문맥에서 보자면 이 둘은 동등하다.

    Yes, I'm conflating OO and Java. In the context of Scala I think it's fair to equate the two.


    2

    그의 많은 통찰들 중 하나.

    One of them!


    3

    PureScript가 이 아이디어를 더 강화했다. 살펴볼만하다.

    PureScript takes this idea further, and is worth looking into.


    4

    나는 클로져 설계와 관련된 논의에서, 설계를 우리 자신에게 설명하고, 설계의 일관성을 검증하고, 결론을 정리하는 과정에서 하스켈시그너쳐를 이용했던 멋진 경험이 있다. 맞다, 클로져 논의였다. 하스켈의 표기법은 언어 차원을 훨씬 넘어서는 가치가 있다.

    I've had some great Clojure design discussions where we've used Haskell signatures to explain ourselves, verify the consistency of the design, and to summarise our conclusions. Yes, Clojure discussions. Haskell's notation has a value that extends far beyond the language.


    5

    정확한 정의는 ‘man perlvar’를 살펴보라.

    See man perlvar for the exact definition.



    참조 사이트:


Designed by Tistory.