유해한 것으로 간주되는 반품? 코드가 없으면 코드가 작동 할 수 있습니까?


45

좋아, 제목은 약간의 clickbaity이지만 진지하게 말하고 있습니다. 잠시 동안 킥을 요구하지 마십시오 . 방법이 객체 지향 방식 으로 메시지 로 사용되도록 장려하는 방법이 마음에 듭니다. 그러나 이것은 내 머릿속에서 괴롭히는 잔소리가 있습니다.

잘 작성된 코드가 동시에 OO 원칙과 기능적 원칙을 따를 수 있다고 생각합니다. 나는 이러한 아이디어를 조정하려고 노력하고 있으며 내가 착륙 한 큰 문제는 return입니다.

순수한 함수에는 두 가지 특성이 있습니다.

  1. 동일한 입력으로 반복해서 호출하면 항상 같은 결과가 나타납니다. 이는 변경할 수 없음을 의미합니다. 상태는 한 번만 설정됩니다.

  2. 부작용이 없습니다. 호출로 인한 유일한 변경은 결과를 생성하는 것입니다.

return결과를 전달하는 방식으로 사용하지 않을 경우 어떻게 순전히 기능을 수행 할 수 있습니까?

텔은 요구하지 않는 일부 부작용을 고려할 것을 사용하여 아이디어 작품. 객체를 다룰 때 내부 상태에 대해 묻지 않습니다. 나는 내가해야 할 일을 말하고 내부 상태를 사용하여 내가 한 일로 무엇을 해야할지 파악합니다. 내가 말하면 나는 그 일을 묻지 않습니다. 나는 그것이 지시받은 것에 대해 무언가를했을 것으로 기대합니다.

나는 Tell, Do n't Ask를 캡슐화의 다른 이름 이상으로 생각합니다. 내가 사용했을 때 나는 return무엇이 나를 불렀는지 전혀 모른다. 나는 그것이 프로토콜이라고 말할 수 없으며, 내 프로토콜을 다루도록 강요해야합니다. 많은 경우에 내부 상태로 표시됩니다. 노출되는 것이 정확하게 상태가 아니더라도 일반적으로 상태 및 입력 인수에 대해 약간의 계산이 수행됩니다. 인터페이스를 통해 응답하면 결과를 내부 상태 나 계산보다 의미있는 것으로 마사지 할 수 있습니다. 그것은 메시지 전달 입니다. 이 예제를 참조하십시오 .

과거에는 디스크 드라이브에 실제로 디스크가 있고 휠이 너무 차가워서 손가락으로 만질 수 없을 때 엄지 드라이브가 자동차에서 한 일이었던 때, 나는 성가신 사람들이 매개 변수가있는 기능을 어떻게 생각하는지 배웠습니다. void swap(int *first, int *second)매우 편리해 보였지만 결과를 반환하는 함수를 작성하도록 권장되었습니다. 그래서 나는 이것을 믿음으로 생각하고 그것을 따르기 시작했습니다.

그러나 이제는 사람들 이 결과물을 보내는 위치를 객체로 구성하여 제어 할 수있는 아키텍처를 구축 하는 사람들이 있습니다. 다음은 구현 예 입니다. 출력 포트 객체를 주입하는 것은 다시 한 번 out 매개 변수 아이디어와 비슷합니다. 그러나 그것이 바로 요청하지 않는 대상이 다른 대상에게 수행 한 작업을 알려주는 방법입니다.

부작용에 대해 처음 알게되었을 때 출력 매개 변수와 같은 것으로 생각했습니다. 우리는 그 일 중 일부가 놀라운 방식으로, 즉 return result대회 를 따르지 않음으로써 사람들을 놀라게하지 말라고 들었습니다 . 이제 부작용이 발생하는 병렬 비동기 스레딩 문제가 있다는 것을 알고 있지만 반환은 실제로 결과를 스택에 푸시하여 나중에 호출 할 수 있도록하는 규칙입니다. 그게 다야.

내가 정말로 물어보고 싶은 것 :

return모든 부작용을 피하고 자물쇠없이 실 안전을 얻는 유일한 방법 입니까? 아니면 순전히 기능적인 방식으로 묻지 말아야 합니까?


3
Command Query Separation을 무시하지 않기로 선택한 경우 문제가 해결 된 것으로 생각하십니까?
rwong

30
발 차기에서 자신을 찾는 것이 특정 상황의 장단점을 추론하기보다는 교리 중심 설계에 참여하고 있음을 나타내는 것일 수 있습니다.
Blrfl

3
일반적으로 사람들이 "반환"에 대해 해로운 것에 대해 이야기 할 때, 그것은 기능적인 것이 아니라 구조화 된 프로그래밍과 루틴의 끝에 단일 리턴 문 (그리고 아마도 if / else 블록의 양쪽 끝에 있을 것) 에 반대한다고 말하고 있습니다. 그 자체는 마지막 요소입니다).
Random832

16
@ jameslarge : 거짓 이분법. 독단적 사고로 자신을 디자인에 몰두시키는 것은 Wild West / 모든 것이 접근하는 것과 같은 것이 아닙니다. 요점은 교리가 좋고 단순하며 명백한 코드를 방해하지 않도록하는 것입니다. 보편적 인 법은 부족을위한 것이다. 문맥 은 왕을위한 것이다.
Nicol Bolas

4
귀하의 질문에 분명하지 않은 한 가지가 있습니다 : 당신은 '반환'을 사용하여 맹세했다고 말하지만, 당신이 그것을 다른 개념과 명시 적으로 관련시키지 않거나 당신이 이것을 한 이유를 말할 수있는 한. 결과 생성을 포함하여 순수한 함수의 정의와 결합하면 해결할 수없는 것을 만듭니다.
Danikov

답변:


96

함수에 부작용이없고 아무 것도 반환하지 않으면 함수는 쓸모가 없습니다. 그렇게 간단합니다.

그러나 규칙 의 글자 를 따르고 근본적인 추론을 무시하고 싶다면 약간의 치트를 사용할 수 있다고 생각합니다 . 예를 들어 out 매개 변수를 사용하면 반환을 사용하지 않는다고 엄격하게 말합니다. 그러나 여전히 더 복잡한 방식으로 수익과 정확히 동일합니다. 따라서 반환이 이유 가 잘못되었다고 생각 되면 out 매개 변수를 사용하는 것이 동일한 기본 이유로 분명히 나쁩니다.

더 복잡한 컨닝을 사용할 수 있습니다. 예를 들어 Haskell은 실제로 부작용을 일으킬 수있는 IO 모나드 트릭으로 유명하지만 이론적으로 볼 때 여전히 부작용이있는 것은 아닙니다. 연속 전달 스타일은 코드를 스파게티로 바꾸는 대가로 수익을 피할 수있는 또 다른 방법입니다.

결론은 바보 같은 트릭이없고 부작용이없는 함수의 두 가지 원칙과 "반환 없음"은 단순히 호환되지 않는다는 것입니다. 또한 나는 둘 다 처음에는 실제로 나쁜 원칙 (독점)이라고 지적하지만 그것은 다른 토론입니다.

"말하고 묻지 말 것"또는 "부작용 없음"과 같은 규칙은 보편적으로 적용될 수 없습니다. 항상 상황을 고려해야합니다. 부작용이없는 프로그램은 말 그대로 쓸모가 없습니다. 순수한 기능적 언어조차도 인정합니다. 오히려 그들은 코드의 순수한 부분을 부작용이있는 부분과 분리 하려고 노력합니다 . Haskell의 State 또는 IO 모나드 포인트는 부작용을 피할 수 없다는 것이 아닙니다. 부작용을 피할 수는 없지만 부작용의 존재는 명시 적으로 함수 시그니처로 표시 됩니다.

tell-dont-ask 규칙은 다른 종류의 아키텍처, 즉 프로그램의 객체가 서로 통신하는 독립적 인 "배우"인 스타일에 적용됩니다. 각 액터는 기본적으로 자율적이고 캡슐화되어 있습니다. 메시지를 보낼 수 있으며 반응 방법을 결정하지만 외부에서 액터의 내부 상태를 확인할 수는 없습니다. 즉, 메시지가 액터 / 오브젝트의 내부 상태를 변경하는지 알 수 없습니다. 상태 및 부작용은 의도적 으로 숨겨져 있습니다.


20
@CandiedOrange : 많은 호출 계층이 개념적으로 아무것도 변경하지 않지만 메소드에 직접 또는 간접적으로 부작용이 있는지 여부. 여전히 부작용입니다. 그러나 요점은 부작용이 주입 된 물체를 통해서만 발생하여 어떤 종류의 부작용이 가능한지를 제어한다는 것이 좋은 디자인 인 것 같습니다. 부작용이 없습니다. 좋은 OO이지만 순수하게 기능하지는 않습니다.
JacquesB

12
@LightnessRacesinOrbit : 자동 모드의 grep에는 사용될 프로세스 리턴 코드가 있습니다. 그것이 없다면, 그것은 실제로 쓸모가 없을 것입니다
unperson325680

10
@progo : 리턴 코드는 부작용이 아닙니다. 그건 효과. 우리가 부작용이라고 부르는 것은 그것이 반환 코드가 아니기 때문에 부작용이라고 불립니다.)
Monica와 Lightness Races

8
@Cubic 그게 요점입니다. 부작용이없는 프로그램은 쓸모가 없습니다.
Jens Schauder

5
@mathreadler 부작용입니다 :)
Andres F.

32

묻지 말고 몇 가지 기본적인 가정이 있습니다.

  1. 개체를 사용하고 있습니다.
  2. 개체의 상태가 있습니다.
  3. 개체의 상태는 동작에 영향을줍니다.

이러한 것들은 순수한 기능에는 적용되지 않습니다.

왜 우리에게 "말하지 말아라"라는 규칙이 있는지 검토해 봅시다. 이 규칙은 경고 및 알림입니다. 다음과 같이 요약 할 수 있습니다.

수업이 자체 상태를 관리하도록합니다. 상태를 묻지 말고 해당 상태에 따라 조치를 취하십시오. 학생들에게 원하는 것을 말하고 자신의 상태에 따라 무엇을해야할지 결정하게하십시오.

달리 말하면, 클래스는 자신의 상태를 유지하고 그에 따라 행동 할 책임이 전적으로 있습니다. 이것이 캡슐화의 모든 것입니다.

에서 파울러 :

Tell-Don't-Ask 는 사람들이 객체 지향이 해당 데이터에서 작동하는 기능과 데이터를 묶는 것임을 기억하는 데 도움이되는 원칙입니다. 객체에 데이터를 요구하고 그 데이터에 대해 행동하는 대신 객체에게 무엇을해야하는지 알려 주어야합니다. 이를 통해 데이터와 함께 동작을 객체로 옮길 수 있습니다.

다시 말하지만,이 중 어느 것도 순수한 기능과 관련이 없으며, 클래스의 상태를 외부 세계에 노출시키지 않는 한 불완전한 기능도 없습니다. 예 :

TDA 위반

var color = trafficLight.Color;
var elapsed = trafficLight.Elapsed;
If (color == Color.Red && elapsed > 2.Minutes)
    trafficLight.ChangeColor(green);

TDA 위반이 아님

var result = trafficLight.ChangeColor(Color.Green);

또는

var result = await trafficLight.ChangeColorWhenReady(Color.Green);     

후자의 예에서, 신호등은 상태 및 동작의 제어를 유지한다.


잠깐만, 클로저는 순수 할 수 있습니다. 그것들은 상태를 가지고 있습니다 (어휘 범위라고 부릅니다). 어휘 범위는 그들의 행동에 영향을 줄 수 있습니다. 개체가 관련된 경우에만 TDA가 관련되어 있습니까?
candied_orange

7
@CandiedOrange 클로저는 닫힌 바인딩을 수정하지 않은 경우에만 순수합니다. 그렇지 않으면 클로저에서 반환 된 함수를 호출 할 때 참조 투명성이 손실됩니다.
Jared Smith

1
@JaredSmith이며 객체에 대해 이야기 할 때 똑같지 않습니까? 이것은 단순히 불변성 문제가 아닌가?
candied_orange

1
@bdsl-이제이 유형에 대한 모든 토론이 trafficLight.refreshDisplay 예제와 함께 진행되는 위치를 실수로 지적했습니다. 규칙을 준수하면 원래 코더 만 이해할 수있는 매우 유연한 시스템으로 연결됩니다. 심지어 몇 년이 지난 후에도 원래의 코더조차도 그들이 한 일을 이해하지 못할 것이라고 생각합니다.
덩크

1
"다른 개체를 열지 말고 용기를 보지 말고 다른 개체 방법으로 자신의 내장을 흘리십시오."
Joker_vD

30

객체를 다룰 때 내부 상태에 대해 묻지 않습니다. 나는 내가해야 할 일을 말하고 내부 상태를 사용하여 내가 한 일로 무엇을 해야할지 파악합니다.

당신은 그 요구하지 않는 내부 상태 는 경우는 요구하지 않는, 모두에서 내부 상태를 가지고 하나.

또한 묻지 마십시오! 메소드 내부의 명령문 에 의해 제공되는 리턴 값의 형태로 결과를 얻지 못한다는 의미 는 아닙니다return . 그것은 당신이 어떻게하는지 신경 쓰지 않는다는 것을 암시 하지만 그 처리를하십시오! . 때로는 즉시 처리 결과를 원합니다 ...


1
그러나 CQS는 상태 수정과 결과 가져 오기가 분리되어야 함을 의미합니다
jk.

7
@jk. 평소처럼 : 당신은 분리해야 일반적으로 상태 변경을 하고 그 결과를 반환 하지만, 드문 경우에 그것을 결합하는 타당한 이유가있다. 예 : iterators next()메소드는 현재 객체를 반환 할뿐만 아니라 다음 호출이 다음 객체를 반환하도록 반복기 내부 상태도 변경해야합니다.
Timothy Truckle

4
바로 그거죠. OP의 문제는 단순히 오해 / 오용이있는“말하지 말아라”때문이라고 생각합니다. 그리고 그 오해를 고치면 문제가 해결됩니다.
Konrad Rudolph

@ KonradRudolph Plus, 나는 이것이 유일한 오해라고 생각하지 않습니다. "순수 기능"에 대한 설명에는 "상태는 한 번만 설정됩니다"가 포함됩니다. 또 다른 의견은 그것이 폐쇄의 맥락을 의미 할 수 있다고 말하지만, 문구는 나에게 이상하게 들립니다.
이즈 카타

17

만약 당신 return이 "유해한" 것으로 생각한다면 (사진에 머물러있는), 대신에

ResultType f(InputType inputValue)
{
     // ...
     return result;
}

메시지 전달 방식으로 작성하십시오.

void f(InputType inputValue, Action<ResultType> g)
{
     // ...
     g(result);
}

만큼 fg부작용 무료입니다 함께 체인은 무료뿐만 아니라 부작용이 될 것입니다. 이 스타일은 Continuation-passing style 과 유사하다고 생각합니다 .

이것이 실제로 "더 나은"프로그램으로 이어질 경우, 일부 규칙을 위반하기 때문에 논쟁의 여지가 있습니다. 독일 소프트웨어 엔지니어 인 Ralf Westphal은이 문제를 해결하기 위해 전체 프로그래밍 모델을 만들었으며, "Flow Design"이라는 모델링 기술을 사용하여 "Event Based Components"라고 불렀습니다.

몇 가지 예를 보려면 이 블로그 항목 의 "이벤트로 번역"섹션에서 시작 하십시오 . 전체 접근 방식을 위해서는 그의 전자 책 "Messaging as a Programming model-Doing OOP you like it"을 추천 합니다.


24
If this really leads to "better" programs is debatable우리는이 세기의 첫 10 년 동안 JavaScript로 작성된 코드 만 살펴 봐야합니다. Jquery와 플러그인은이 패러다임 콜백에 취약했습니다 . 특정 시점에서 중첩 된 콜백이 너무 많아 디버깅이 악몽이되었습니다. 소프트웨어 공학의 편심과 "원칙"에 관계없이 인간은 여전히 ​​코드를 읽어야합니다.
Laiv

1
심지어 어느 시점에서 부작용을 수행하는 조치를 제공해야하거나 CPS 파트
jk

12
@Laiv CPS는 컴파일러를위한 최적화 기술로 개발되었으므로 실제로 프로그래머가 직접 코드를 작성하는 사람은 아무도 없습니다.
Joker_vD

3
@CandiedOrange 슬로건 형태로, "반환은 단지 무엇을해야하는지 계속 말하고 있습니다". 실제로 Scheme의 제작은 Hewitt의 Actor 모델을 이해하려고 동기를 부여했으며 배우와 클로저가 같은 것이라고 결론을 내 렸습니다.
Derek Elkins

2
가설 적으로, 전체 애플리케이션을 아무 것도 반환하지 않는 일련의 함수 호출로 작성할 수 있습니다. 밀접하게 연결되어 있지 않다면 포트가 필요하지 않습니다. 그러나 대부분의 제정신 애플리케이션은 사물을 반환하는 함수를 사용합니다. 왜냐하면 제정신이기 때문입니다. 그리고 나는 내 대답에서 적절하게 시연했다고 생각하는 return것처럼 객체의 상태를 지휘하지 않는 한 함수의 데이터를 사용하고 Tell Do n't Ask를 계속 준수 할 수 있습니다 .
Robert Harvey

7

메시지 전달은 본질적으로 효과적입니다. 당신이 경우 에 개체를 것을, 당신은 뭔가에 영향을 미칠 것으로 예상된다. 메시지 핸들러가 순수한 경우 메시지를 보낼 필요가 없습니다.

분산 액터 시스템에서 작업 결과는 일반적으로 원래 요청 의 발신자 에게 메시지로 다시 전송됩니다 . 메시지의 보낸 사람은 액터 런타임에 의해 암시 적으로 사용 가능하게되거나 메시지의 일부로 명시 적으로 전달됩니다. 동기식 메시지 전달에서 단일 응답은 return명령문 과 유사 합니다. 비동기 메시지 전달에서 응답 메시지를 사용하면 여러 액터에서 동시에 처리하면서 결과를 계속 전달할 수 있으므로 특히 유용합니다.

결과를 명시 적으로 전달해야하는 "보낸 사람"을 전달하면 기본적으로 연속 전달 스타일 또는 끔찍한 매개 변수가 전달됩니다 (단, 메시지를 직접 변경하는 대신 메시지를 전달하는 것 제외).


5

이 전체 질문은 나를 '레벨 위반'으로 생각합니다.

주요 프로젝트에는 최소한 다음 레벨이 있습니다.

  • 전자 상거래 플랫폼과 같은 시스템 수준
  • 하위 시스템 수준 (예 : 사용자 유효성 검사 : 서버, AD, 프런트 엔드)
  • 개별 프로그램 레벨 (예 : 위의 구성 요소 중 하나)
  • 액터 / 모듈 레벨 [언어에 따라 흐릿함]
  • 방법 / 기능 수준.

그리고 개별 토큰까지 내려갑니다.

메소드 / 함수 레벨에서 엔티티가 리턴하지 않아야 할 필요는 없습니다 (단지 리턴하더라도 this). 그리고 (귀하의 설명에서) 액터 레벨의 엔티티가 (어쩌면 불가능한 언어에 따라) 아무것도 반환하지 않아도됩니다. 나는 혼란이 두 레벨을 팽팽하게 만드는 데 있다고 생각하며, 주어진 객체가 실제로 여러 레벨에 걸쳐 있더라도 명확하게 추론해야한다고 주장합니다.


2

"tell, do n't ask"의 OOP 원칙과 순수한 함수의 기능적 원칙을 모두 준수하고 싶다고 말하지만, 그것이 어떻게 리턴 문을 피하게했는지는 잘 모르겠습니다.

이 두 가지 원칙을 따르는 비교적 일반적인 대안은 return 문에 올인하고 getter와 함께 불변 개체를 사용하는 것입니다. 그런 다음 접근 방식은 일부 getter가 원래 객체의 상태를 변경하는 대신 새로운 상태의 유사한 객체를 반환하도록하는 것입니다.

이 접근법의 한 예는 Python 내장 tuplefrozenset데이터 유형입니다. 고정 세트의 일반적인 사용법은 다음과 같습니다.

small_digits = frozenset([0, 1, 2, 3, 4])
big_digits = frozenset([5, 6, 7, 8, 9])
all_digits = small_digits.union(big_digits)

print("small:", small_digits)
print("big:", big_digits)
print("all:", all_digits)

다음을 인쇄하면 공용체 메소드가 기존 오브젝트에 영향을 미치지 않고 자체 상태로 새로운 고정 세트를 작성 함을 보여줍니다.

작음 : frozenset ({0, 1, 2, 3, 4})

큰 : frozenset ({5, 6, 7, 8, 9})

모두 : frozenset ({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})

유사한 불변 데이터 구조의 또 다른 광범위한 예는 Facebook의 Immutable.js 라이브러리입니다. 두 경우 모두 이러한 구성 요소로 시작하여 동일한 원칙을 따르는 더 높은 수준의 도메인 개체를 구축하여 기능적인 OOP 접근 방식을 달성함으로써 데이터와 그에 대한 이유를보다 쉽게 ​​캡슐화 할 수 있습니다. 또한 불변성을 통해 잠금에 대해 걱정할 필요없이 스레드간에 이러한 객체를 공유 할 수 있다는 이점이 있습니다.


1

잘 작성된 코드가 동시에 OO 원칙과 기능적 원칙을 따를 수 있다고 생각합니다. 나는 이러한 아이디어를 조정하려고 노력하고 있으며 내가 착륙 한 큰 문제는 돌아온 것입니다.

나는 return본질적으로 명령적이고 기능적인 프로그래밍 (자연스럽게 모든 이점을 얻지는 않지만 두 가지에 대한 사자의 몫을 얻으려고 노력)의 이점 중 일부를 조정하기 위해 최선을 다하고 있지만 실제로는 많은 경우에 나를 위해 간단한 패션.

return진술 을 피하려고 노력하는 것과 관련하여 , 나는 지난 몇 시간 동안이 문제를 해결하려고 노력했으며 기본적으로 내 뇌에 여러 번 오버플로되었습니다. 나는 단지 무엇을해야하는지 알려주는 매우 자율적 인 객체를 선호하여 가장 강력한 수준의 캡슐화와 정보 숨기기를 적용한다는 점에서 그 매력을 볼 수 있으며, 더 나은 것을 얻으려고 노력할 때 아이디어의 끝을 탐구하는 것을 좋아합니다. 그들이 어떻게 작동하는지 이해합니다.

우리가 신호등 예제를 사용한다면, 순진한 시도는 그 신호등을 둘러싸고있는 전 세계에 대한 그러한 신호등에 대한 지식을 제공하고자 할 것이며, 이는 커플 링 관점에서 바람직하지 않을 것입니다. 따라서 올바르게 이해하면 파이프 라인을 통해 데이터가 아닌 메시지와 요청을 더 전파하는 I / O 포트 개념을 일반화하고 기본적으로 이러한 객체를 원하는 상호 작용 / 요청으로 주입 서로를 모르는 동안.

노드 파이프 라인

여기에 이미지 설명을 입력하십시오

그리고 그 다이어그램은 이것을 스케치하려고하는 한 (그리고 간단하면서도 계속 변경하고 다시 생각해야했던) 정도입니다. 이 레벨의 디커플링 및 추상화 수준의 디자인은 코드 형식으로 추론하기가 매우 어려울 것이라고 생각하는 경향이 있습니다. 복잡한 세계를 위해 이러한 모든 것을 연결하는 조정자는 매우 어려울 수 있기 때문입니다. 원하는 파이프 라인을 만들기 위해 이러한 모든 상호 작용 및 요청을 추적하십시오. 그러나 시각적 인 형태로, 이러한 것들을 그래프로 그리고 모든 것을 연결하고 대화식으로 일어나는 것을 보는 것이 합리적 일 수 있습니다.

부작용 측면에서 볼 때 이러한 요청이 호출 스택에서 각 스레드가 수행 할 명령 체인으로 이어질 수 있다는 의미에서 "부작용"이 없음을 알 수 있습니다 (예 : 이러한 명령이 실제로 실행될 때까지 외부 세계와 관련된 상태를 변경하지 않기 때문에 실용적인 의미에서 "부작용"으로서-대부분의 소프트웨어에서 나에게 실질적인 목표는 부작용을 제거하는 것이 아니라이를 지연시키고 집중시키는 것입니다) . 또한 명령 실행은 기존 세계를 변경하는 대신 새로운 세계를 출력 할 수 있습니다. 내 뇌는이 아이디어를 프로토 타이핑하려는 시도를하지 않고이 모든 것을 이해하려고 노력하는 데 실제로 세금이 부과된다. 나는 또한

작동 원리

명확히하기 위해 실제로 어떻게 프로그래밍하는지 상상하고있었습니다. 내가 작동하는 방식은 실제로 사용자 엔드 (프로그래머의) 워크 플로우를 캡처하는 위의 다이어그램이었습니다. 신호등을 월드로 드래그하고 타이머를 드래그하여 경과 시간을 줄 수 있습니다 ( "구축"시). 타이머에는 On Interval이벤트 (출력 포트)가 있으며 신호등에 연결하여 해당 이벤트에서 빛이 색상을 순환하도록 지시합니다.

그러면 신호등이 특정 색상으로 전환 할 때 다음과 같은 출력 (이벤트)을 내 보냅니다 On Red.이 시점에서 보행자를 세상으로 끌고 보행자에게 걷기 시작하도록 알리거나 새를 끌어다 놓을 수 있습니다. 빛이 붉어지면 새들에게 날아가 날개를 펄럭 거리라고하거나 ... 빛이 붉어지면 폭탄을 터뜨 리라고합니다. 이 추상적 인 입 / 출력 개념을 통해 무엇을해야하는지 간접적으로 알리는 것 외에는 아무것도하지 않습니다.

그리고 그들은 그들의 상태를 완전히 캡슐화하고 그것에 대해 아무것도 공개하지 않습니다 (이 "이벤트"가 TMI로 간주되지 않는 한, 내가 많은 것을 재고해야 할 시점입니다), 그들은 간접적으로 할 일을 서로에게 말하지 않습니다. 그리고 그들은 서로 분리되어 있습니다. 이 일반화 된 입 / 출력 포트 추상화를 제외하고는 아무것도 알 수 없습니다.

실제 사용 사례?

이 유형의 항목이 특정 도메인에서 고급 도메인 별 임베디드 언어로 유용하여 주변 세계에 대해 전혀 모르는 모든 자율 객체를 조율하고 내부 상태 포스트 구성을 전혀 노출시키지 않으며 기본적으로 요청을 전파하는 데 유용합니다. 우리는 서로 마음의 내용을 바꾸고 조정할 수 있습니다. 지금은 이것이 매우 도메인 특정 적이라고 생각하거나 어쩌면 그것에 대해 충분히 생각하지 않았습니다. 왜냐하면 정기적으로 개발하는 것들로 뇌를 감싸기가 매우 어렵 기 때문입니다. 텔을 해석해야한다면, 그러한 사지에 묻지 말고 상상할 수있는 가장 강력한 캡슐화 수준을 원하십시오. 그러나 특정 도메인에서 높은 수준의 추상화로 작업하는 경우

신호 및 슬롯

이 디자인은 구현 방식의 뉘앙스를 많이 고려하지 않으면 기본적으로 신호와 슬롯이라는 것을 깨달을 때까지 이상하게 보였습니다. 나에게 주된 질문은 말하기, 묻지 말고 피하는 정도에 따라 엄격하게 준수하면서 그래프에서 이러한 개별 노드 (객체)를 얼마나 효과적으로 프로그래밍 return할 수 있으며 돌연변이없이 상기 그래프를 평가할 수 있는지 여부입니다. 병렬 (예 : 잠금 없음). 마법의 이점은 이러한 것들을 잠재적으로 연결하는 방법이 아니라 돌연변이가없는 이러한 캡슐화 수준으로 어떻게 구현 될 수 있는가에 있습니다. 이 두 가지가 모두 실현 가능해 보이지만 그것이 얼마나 광범위하게 적용되는지는 확실하지 않으며, 잠재적 유스 케이스를 통해 작업을 시도하는 데 어려움을 겪고 있습니다.


0

나는 확실성의 누출을 분명히 본다. "부작용"은 잘 알려져 있고 일반적으로 이해되는 용어로 보이지만 실제로는 그렇지 않습니다. 정의에 따라 (실제로 OP에서 누락 됨) 부작용이 완전히 필요하거나 (@JacquesB가 설명 한대로) 자비 롭게 받아 들여지지 않을 수 있습니다. 또는 해명을 향한 한 걸음을, 필요성 구별이 원하는 부작용 중 하나는 숨길 수없는 같은 과 (그것의 아무것도하지만 방법은 명시 적없는이 지점에서 유명한 하스켈의 IO가 나온다) 바람직하지 않은 A와 부작용 코드 버그 및 그런 종류의 결과 . 그것들은 매우 다른 문제이므로 다른 추론이 필요합니다.

그래서 나는 스스로를 표현하는 것부터 시작하는 것이 좋습니다 : "우리는 부작용을 어떻게 정의하고 주어진 정의 (들)가"반환 "진술과의 상관 관계에 대해 무엇을 말합니까?"


1
"이 시점에서 유명한 하스켈의 IO가 등장합니다 : 그것은 명백한 방법 일뿐입니다."-명시 성은 하스켈의 모나 딕 IO의 이점이지만, 또 다른 점이 있습니다. 부작용을 완전히 격리시키는 수단을 제공합니다. 일반적 으로 효율성 구현 으로 인해 일반적인 구현이 실제로 는 그렇지 않지만 개념적으로는 사실입니다. IO 모나드는 완전히 외부의 일부 환경으로 명령을 반환하는 방법으로 간주 될 수 있습니다. Haskell 프로그램 및 완료 후 계속할 기능에 대한 참조
Jules
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.