Elixir 가드에서 `or`와 가드 실패가 어떻게 예상 밖의 결과를 만드는지 간단한 퀴즈로 살펴봅니다.
간단한 퀴즈로 시작해 봅시다.
다음과 같이 정의된 모듈이 있다고 합시다:
defmodule Foo do
def a(x) when is_integer(x) or is_map_key(x, :foo), do: true
def a(x), do: false
def b(x) when is_map_key(x, :foo) or is_integer(x), do: true
def b(x), do: false
end
이 질문들에 답해 보세요.
Q: Foo.a(%{foo: 21})의 결과는 무엇일까요?
true
false
WRONG
RIGHT
이것은 간단합니다.
가드를 확인하면 조건이 하나 있습니다: is_integer(x) or is_map_key(x, :foo). 첫 번째는 false를 반환하고, 두 번째는 true를 반환하므로 Boolean 대안의 결과는 true가 되고 첫 번째 절이 매치됩니다.
Q: Foo.a(37)의 결과는 무엇일까요?
true
false
WRONG
RIGHT
이것도 마찬가지로 간단합니다.
가드를 확인하면 조건이 하나 있습니다: is_integer(x) or is_map_key(x, :foo). 첫 번째는 true를 반환하고, or 연산자는 단락 평가를 하므로 두 번째는 아예 실행되지 않습니다.
Q: Foo.b(%{foo: 21})의 결과는 무엇일까요?
true
false
WRONG
RIGHT
다시 말해, 앞선 질문들과 비슷합니다.
가드를 확인하면 조건이 하나 있습니다: is_map_key(x, :foo) or is_integer(x). 첫 번째가 true를 반환하고 나머지는 단락 평가됩니다.
Q: Foo.b(37)의 결과는 무엇일까요?
true
false
WRONG
RIGHT
이런, 뭔가 달라졌습니다…
다시 가드를 확인하면 조건은 하나입니다: is_map_key(x, :foo) or is_integer(x). 첫 번째 절 is_map_key(x, :foo)에 도달하는데, 이것은 false를 반환하는 것이 아니라 실패합니다. 가드 함수 중 하나에서의 실패는 false로 변환되지 않고, 대신 전체 가드 표현식을 실패하게 만듭니다. 이는 is_integer(x) 부분이 절대 호출되지 않는다는 뜻입니다.
이 동작은 많은 Elixir 개발자에게 종종 놀랍게 느껴집니다. 겉보기에는 Boolean 연산자의 교환 법칙을 깨는 것처럼 보이기 때문입니다. 하지만 엄밀히 말하면, 단락 평가 때문에 이것들은 원래부터 교환 가능하지 않았습니다.
작성 시점 기준(Elixir 1.20.1, OTP 29)으로 Elixir는 이 문제에 대해 경고를 내지 않는 것으로 보입니다.
∎