키워드 나 함수보다 연산자가 더 명확합니까? [닫은]


14

약간 주관적이지만 연산자를 사용하기 쉽고 명확하게 만드는 요소를 이해하기를 바랍니다. 나는 최근에 언어 디자인을 고려해 왔으며, 항상 돌아 다니는 한 가지 문제는 언어에서 핵심 조작을 연산자로 할 때와 키워드 또는 함수를 사용할 때입니다.

Haskell은 사용자 지정 연산자를 쉽게 만들 수 있고 종종 새 데이터 형식에 여러 연산자가 패키지되어 제공되기 때문에 다소 악명이 높습니다. 파섹 라이브러리는, 예를 들어, 같은 보석과 함께 파서를 결합하는 사업자의 톤과 함께 제공 >.하고 .> 심지어 그들이 지금 무엇을 의미하는지 기억 수는 없지만, 내가 기억했다하면 매우 쉽게 작업에있는 그들을 기억하는 일 그들은 실제로 의미합니다. 같은 함수 호출 leftCompose(parser1, parser2)이 더 좋았습니까? 확실히 더 장황하지만 어떤면에서는 더 명확합니다.

C와 같은 언어로 된 연산자 오버로드도 비슷한 문제이지만 익숙하지 않은 연산자의 의미 +를 비정상적으로 새로운 의미 로 오버로드하는 추가 문제로 인해 혼란스러워집니다 .

새로운 언어에서 이것은 꽤 어려운 문제처럼 보일 것입니다. 예를 들어 F #에서 캐스팅은 C # 스타일 캐스트 구문이나 자세한 VB 스타일 대신 수학적으로 파생 된 형식 캐스팅 연산자를 사용합니다. C # : (int32) xVB : CType(x, int32)F # :x :> int32

이론적으로 새로운 언어는 대부분의 내장 기능을위한 연산자를 가질 수 있습니다. 대신 def하거나 dec또는 var변수 선언, 왜하지 않는 ! name@ name또는 비슷한. 선언 @x := 5대신 에 바인딩을 따라 단축 : 대신 declare x = 5또는 let x = 5 대부분의 코드는 많은 변수 정의가 필요합니다. 왜 안됩니까?

운영자는 언제 명확하고 유용하며 언제 가려 집니까?



1
Java의 운영자 과부하 부족에 대해 불평 한 1,000 명의 개발자 중 한 명이이 질문에 대답하기를 바랍니다.
smp7d

1
나는 질문을 타이핑 할 때 APL을 생각했지만 몇 가지 방법으로 요점을 명확히하고 다소 덜 주관적인 영역으로 옮깁니다. 나는 대부분의 사람들이 APL이 극도의 연산자를 통해 사용 편의성에서 무언가를 잃어 버릴 것이라고 생각할 수 있지만, 언어에 연산자 과부하가 없을 때 불평하는 사람들의 수는 일부 기능에 적합하다는 것을 분명히 말하고 있습니다. 운영자 역할을합니다. 금지 된 사용자 지정 연산자와 연산자 외에는 실제 구현 및 사용에 대한 지침을 숨겨야합니다.
CodexArcanum

내가 알다시피, 연산자 오버로드 부족은 사용자 정의 유형보다 기본 유형에 특권을 부여하기 때문에 불쾌합니다 (자바는 다른 방법으로도 수행합니다). 하스켈 스타일의 커스텀 연산자에 대해서는 훨씬 더 애매 모호합니다. 문제에 대한 공개 초대처럼 보입니다 ...
comingstorm

2
@comingstorm : 실제로 Haskell 방식이 더 좋다고 생각합니다. 다른 방식으로 오버로드 할 수있는 유한 연산자 세트가있는 경우, 종종 다른 컨텍스트 (예 : +문자열 연결 또는 <<스트림) 에서 연산자를 재사용해야합니다 . 반면에 Haskell을 사용하면 연산자는 사용자 정의 이름을 가진 함수이거나 (오버로드되지 않은) 유형 클래스의 일부이므로 다형성이지만 모든 유형에 대해 동일한 논리적 인 작업을 수행합니다. 같은 형식의 서명도 있습니다. 그래서 >>이다 >>모든 유형 결코 조금의 변화가 될 것 없습니다.
Tikhon Jelvis 9

답변:


16

일반적인 언어 디자인 관점에서 함수와 연산자 사이에 차이가있을 필요는 없습니다. 어떤 (또는 가변적 인) arity를 ​​가진 접두사 연산으로 함수를 설명 할 수 있습니다. 키워드는 예약 된 이름을 가진 함수 나 연산자로 볼 수 있습니다 (문법을 설계하는 데 유용함).

이러한 모든 결정은 결국 표기법을 어떻게 읽고 싶고 주관적이라고 말하는 것처럼 모든 사람들이 알고있는 것처럼 수학에 대해 일반적인 대입 연산자를 사용하는 등의 합리적인 합리화를 만들 수 있습니다.

마지막으로 Dijkstra는 그가 사용한 수학적 표기법에 대한 흥미로운 근거를 썼습니다.


4
Dijkstra 논문에 대한 링크를 두 번째로 +1하고 싶습니다.
AProgrammer

훌륭한 링크, 당신은 페이팔 계정을 게시해야했습니다! ;)
Adriano Repetti

8

나에게 더 이상 코드 줄을 소리내어 읽거나 머리에서 읽을 수 없을 때 연산자가 유용하지 않습니다.

예를 들어, declare x = 5같은 읽기 "declare x equals 5"또는 let x = 5같은 읽을 수 "let x equal 5"있지만, 읽기, 소리내어 읽을 때 매우 이해할 수있는, @x := 5같이 읽기 "at x colon equals 5"(또는 "at x is defined to be 5"당신은 수학자 인 경우) 전혀 이해가되지 않습니다.

내 의견으로는, 언어에 익숙하지 않은 합리적으로 똑똑한 사람이 코드를 크게 읽고 이해할 수 있다면 연산자를 사용하지만 그렇지 않으면 함수 이름을 사용하십시오.


5
나는 이해 @x := 5하기 어렵다고 생각하지 않습니다 -나는 아직도 그것을 자신에게 큰소리로 읽습니다 set x to be equal to 5.
FrustratedWithFormsDesigner

3
이 경우 @Rachel :=은 프로그래밍 언어 이외의 수학 표기법에서 더 광범위하게 사용됩니다. 또한, 같은 말 x = x + 1은 약간 터무니 없습니다.
ccoakley

3
아이러니하게도, 나는 일부 사람들이 :=과제로 인식하지 못할 것을 잊었다 . 실제로 몇몇 언어는이를 사용합니다. 스몰 토크는 아마도 가장 잘 알려진 것 같습니다. 할당과 평등이 별도의 운영자 여야하는지 여부는 완전히 다른 웜 캔일 수 있으며, 이미 다른 질문으로 덮여있을 수 있습니다.
CodexArcanum

1
@ccoakley 고마워, 나는 그것이 :=수학에서 사용 되었다는 것을 몰랐다 . 나는 그것을 발견 한 정의 된 "으로 정의된다" 그래서 @x := 5에 영어로 번역 될 것이다 "at x is defined to be 5"여전히 예상대로 많은 의미로하지 않는 나에게하는.
Rachel

1
ASCII에서 왼쪽 화살표가 없기 때문에 Pascal은 : =를 대입으로 사용했습니다.
Vatine

4

운영자는 친숙 할 때 명확하고 유용합니다. 그리고 이는 아마도 선택한 연산자가 이미 설정된 관행으로 (양식, 우선 순위 및 연관성으로) 충분히 근접한 경우에만 과부하 연산자를 수행해야 함을 의미합니다.

그러나 조금 더 파면 두 가지 측면이 있습니다.

구문 (함수 호출 구문의 접두어가 아닌 연산자의 접두어) 및 명명.

구문의 경우, 접두사보다 접두사가 충분히 명확한 또 다른 경우가 있습니다. 즉, 호출이 연결되고 중첩 될 때 친숙해지는 노력을 보장 할 수 있습니다.

비교 a * b + c * d + e * f+(+(*(a, b), *(c, d)), *(e, f))+ + * a b * c d * e f(모두 중위 버전과 동일한 조건에서 분석 할 수 있습니다). (가) 사실 +대신 긴 방법으로 그 중 하나를 앞의 조건을 분리 내 눈에 더 읽기 쉽게 (하지만 당신은 접두사 구문에 필요하지 않은 우선 순위 규칙을 기억해야한다). 이런 방식으로 사물을 합성해야하는 경우 장기적인 혜택은 학습 비용으로 가치가 있습니다. 또한 기호 대신 문자로 연산자 이름을 지정하더라도이 이점을 유지하십시오.

연산자의 이름 지정과 관련하여 기존의 기호 또는 명확한 이름 이외의 것을 사용하면 이점이 거의 없습니다. 예, 더 짧을 수도 있지만 실제로는 비밀이 있으며 이미 알고있는 충분한 이유가 없다면 빨리 잊혀 질 것입니다.

언어 디자인 POV를 사용하는 경우 세 번째 측면은 연산자 세트가 열려 있거나 닫혀 있어야하는지, 연산자를 추가 할 수 있는지 여부와, 우선 순위 및 연관성이 사용자 지정 가능해야하는지 여부입니다. 첫 번째는 신중하고 사용자가 지정할 수있는 우선 순위와 연관성을 제공하지 않는 것이지만 오픈 세트를 사용하는 것에 더 개방적입니다 (오퍼레이터 오버로드를 사용하는 푸시를 증가 시키지만 나쁜 것을 사용하는 것을 감소시킵니다) 유용 할 때 삽입 구문의 이점을 얻으려면).


사용자가 연산자를 추가 할 수 있다면 추가 한 연산자의 우선 순위와 연관성을 설정하지 않겠습니까?
Tikhon Jelvis

@TikhonJelvis, 그것은 대부분 보수적이지만 예제 이외의 용도로 사용할 수 있다면 고려해야 할 몇 가지 측면이 있습니다. 예를 들어, 오버로드 된 세트의 지정된 멤버가 아닌 연산자에 우선 순위 및 연관성을 바인딩하려고합니다 (구문 분석이 완료된 후 멤버를 선택하면 선택이 구문 분석에 영향을 줄 수 없음). 따라서 동일한 연산자를 사용하여 라이브러리를 통합하려면 우선 순위와 연관성에 동의해야합니다. 가능성을 추가하기 전에 왜 소수의 언어가 Algol 68 (AFAIK 없음)을 따르고 정의 할 수 있는지 알아 내려고 노력했습니다.
AProgrammer

Haskell을 사용하면 임의 연산자를 정의하고 우선 순위와 연관성을 설정할 수 있습니다. 차이점은 연산자 자체를 오버로드 할 수 없다는 것 입니다. 일반 함수처럼 작동합니다. 즉, 다른 것에 대해 동일한 연산자를 사용하려는 다른 라이브러리를 가질 수 없습니다. 자신 만의 연산자를 정의 할 수 있으므로 같은 것을 다른 용도로 재사용 할 이유가 훨씬 적습니다.
Tikhon Jelvis

1

기호로서의 연산자는 직관적으로 이해 될 때 유용합니다. +그리고 -거의 모든 언어가 이제까지 자신의 운영자로를 사용하는 이유입니다, 예를 들어, 분명히 덧셈과 뺄셈이다. 비교와 동일 ( <>초등학교에서 가르치는하고, <=그리고 >=당신은 표준 키보드에는 밑줄-비교 키가 없다는 것을 이해하면 기본 비교 직관적 확장입니다.)

*그리고 /덜 즉시 명백하다, 그러나 보편적으로 사용하고 있고 바로 옆에 숫자 키패드에서 자신의 위치 +-키 컨텍스트를 제공하는 데 도움이됩니다. C <<>>같은 범주에 있습니다. 왼쪽 시프트와 오른쪽 시프트가 무엇인지 이해하면 화살표 뒤의 니모닉을 이해하는 것이 어렵지 않습니다.

그런 다음 C 코드를 읽을 수없는 운영자 수프로 바꿀 수있는 정말 이상한 것들을 보게됩니다. (여기서 C를 선택하는 것은 C를 사용하거나 자손 언어를 사용하여 거의 모든 사람에게 익숙한 구문을 가진 연산자가 많은 예제이므로 %연산자입니다 .) 예를 들어 연산자입니다. 누구나 그것이 무엇인지 알고 있습니다 : 그것은 퍼센트 부호입니다 ... 맞습니까? C를 제외하고 100으로 나누는 것과는 아무런 관련이 없습니다. 모듈러스 연산자입니다. 그것은 니모닉으로 제로 의미가 있지만 거기에 있습니다!

부울 연산자는 더 나쁩니다. &int로서 와는 의미가 있습니다,이 두 가지 다른 점을 제외 &하더라도 단지 그들 중 하나가 지금까지, 두 개의 서로 다른 일을하고 작업자는 모두 그들 중 하나가 유효한 어떤 경우에 문법적으로 유효 실제로 의미가 주어진 경우. 그것은 혼란을위한 레시피 일뿐입니다! 또는 , XOR하지 가 mnemonically 유용한 기호를 사용하지, 그리고 중 하나를 일치하지 않기 때문에 통신 사업자는 더 악화된다. 이중 xor 연산자가 없으며 논리 및 비트 단위 는 하나의 기호와 두 배로 된 버전 대신 두 개의 다른 기호를 사용 하지 않습니다 .

그리고 더 나쁘게 만들기 위해 &and *연산자는 완전히 다른 것을 재사용하여 사람과 컴파일러가 구문 분석하기가 더 어려워집니다. (무엇을 A * B의미합니까? 그것은 전적으로 상황에 달려 있습니다 : A유형 또는 변수입니까?)

틀림없이, 나는 Dennis Ritchie와 이야기하지 않았고 그가 언어로 한 디자인 결정에 대해 그에게 물었지만, 그 뒤에는 오퍼레이터의 철학이 "기호를위한 상징"인 것 같은 느낌이 들었습니다.

이것을 C와 동일한 연산자를 가지고 있지만이를 나타내는 다른 철학 인 파스칼과는 대조적입니다. 연산자는 직관적이고 읽기 쉬워야합니다. 산술 연산자는 동일합니다. mod키보드에는 분명히 "모듈러스"를 의미하는 기호가 없기 때문에 모듈러스 연산자는 단어 입니다. 논리 연산자는 and, or, xornot, 그리고 각 하나있다; 컴파일러는 부울 또는 숫자로 작업하는지 여부에 따라 부울 또는 비트 버전이 필요한지 알고 전체 오류 클래스를 제거합니다. 따라서 구문 강조 기능이있는 최신 편집기에서 파스칼 코드를 C 코드보다 훨씬 쉽게 이해할 수 있으므로 연산자와 키워드가 식별자와 시각적으로 구분됩니다.


4
파스칼은 전혀 다른 철학을 나타내지 않습니다. 당신 워스의 논문을 읽어 보면, 그와 같은 것들에 대한 기호를 사용 and하고 or모든 시간을. 그러나 Pascal을 개발할 때 6 비트 문자를 사용하는 Control Data 메인 프레임에서이를 수행했습니다. 즉, 문자 집합이 간단하지 않았다 단순한 이유로, 많은 것을 위해 사용하는 단어에 대한 결정을 강제 많은 기호 공간과 같은 ASCII 같은 등으로 거의. 나는 C와 Pascal을 모두 사용했으며 C가 훨씬 더 읽기 쉽습니다. 파스칼을 선호 할 수도 있지만 사실은 맛이 아닙니다.
Jerry Coffin

Wirth에 대한 @JerryCoffin의 발언에 추가하기 위해 후속 언어 (Modula, Oberon)는 더 많은 기호를 사용하고 있습니다.
AProgrammer

@AProgrammer : 그리고 그들은 어디에도 가지 않았습니다. ;)
Mason Wheeler

나는 |(그리고 확장 해서) 생각 ||하거나 의미가있다. 또한 문법과 같은 다른 상황에서 항상 변경 될 수 있으며 두 가지 옵션을 나누는 것처럼 보입니다.
Tikhon Jelvis 2016 년

1
문자 기반 키워드의 장점은 공간이 기호보다 훨씬 크다는 것입니다. 예를 들어, 파스칼 스타일 언어에는 "모듈러스"및 "나머지"및 정수 대 부동 소수점 나누기 (피연산자 유형 이외의 의미가 다른)에 대한 연산자가 포함될 수 있습니다.
supercat

1

함수가 친숙하고 수학적인 목적을 밀접하게 반영 할 때 연산자는 훨씬 더 읽기 쉽다고 생각합니다. 예를 들어, 더하기 및 빼기를 수행 할 때 +,-등과 같은 표준 연산자는 더하기 또는 빼기보다 더 읽기 쉽습니다. 운영자의 행동을 명확하게 정의해야합니다. 예를 들어 목록 연결에 대한 +의 과부하가 허용됩니다. 이상적으로는 연산에 부작용이 없어서 변경하는 대신 값을 반환합니다.

그래도 접기와 같은 기능에 대한 단축키 연산자로 어려움을 겪었습니다. 분명히 그들에 대한 더 많은 경험은 이것을 용이하게 할 것이지만, 나는 foldRight보다 더 읽기 쉽습니다 /:.


4
어쩌면 사용 빈도가 그것 일 수도 있습니다. fold운영자가 많은 시간을 절약 할만큼 자주 생각하지는 않습니다 . 이것이 LISPy (+ 1 2 3)가 이상하게 보이지만 (add 1 2 3)이 그렇게 적은 이유이기도합니다. 우리는 연산자를 엄격하게 이진으로 생각하는 경향이 있습니다. Parsec의 >>.스타일 연산자는 바보 같을 수 있지만 적어도 Parsec에서 가장 중요한 것은 파서를 결합하는 것이므로 연산자는 많이 사용됩니다.
CodexArcanum

1

연산자의 문제점은 대신 사용할 수있는 감각적 (!) 메소드 이름의 수와 비교하여 소수의 수가 있다는 것입니다. 부작용은 사용자 정의 연산자가 많은 과부하를 유발하는 경향이 있다는 것입니다.

확실히,이 줄 C = A * x + b * c은보다 쓰기와 읽기가 더 쉽습니다 C = A.multiplyVector(x).addVector(b.multiplyScalar(c)).

또는 머리에 모든 연산자의 오버로드 된 버전이 모두 있으면 쓰기가 훨씬 쉽습니다. 그리고 나중에 읽을 수있는 버그를 수정하면서 나중에 읽을 수 있습니다.

자, 거기에서 실행될 대부분의 코드는 괜찮습니다. "프로젝트는 모든 테스트를 통과하고 실행됩니다"-우리가 원했던 모든 소프트웨어에 대해

그러나 중요한 영역에 들어가는 소프트웨어를 사용할 때는 상황이 다르게 작동합니다. 안전에 중요한 것들. 보안. 비행기를 공중에 유지하거나 핵 시설을 계속 운영하는 소프트웨어. 또는 기밀 이메일을 암호화하는 소프트웨어입니다.

감사 코드를 전문으로하는 보안 전문가에게는 악몽이 될 수 있습니다. 풍부한 사용자 정의 연산자와 연산자 오버로드가 혼합되어 어떤 코드가 결국 실행되는지 파악하기가 어려운 불쾌한 상황에 놓일 수 있습니다.

따라서 원래 질문에서 언급했듯이 이것은 매우 주관적인 주제입니다. 그리고 연산자가 어떻게 사용되어야하는지에 대한 많은 제안이 완벽하게 감각적으로 들릴 수 있지만, 소수의 조합만으로도 장기적으로 많은 문제가 발생할 수 있습니다.


0

가장 극단적 인 예는 APL이라고 가정합니다. 다음 프로그램은 "삶의 게임"입니다.

life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

그리고 참조 설명서와 함께 며칠을 보내지 않고 모든 것이 의미하는 바를 해결할 수 있다면 행운을 빕니다!

문제는 거의 모든 사람이 직관적으로 이해하는 일련의 기호가 있다는 것입니다. +,-,*,/,%,=,==,&

나머지는 이해하기 전에 약간의 설명이 필요하며 일반적으로 특정 언어에 따라 다릅니다. 예를 들어, 원하는 배열 구성원 [], () 및 "."을 지정하는 명확한 기호가 없습니다. 사용 되었으나 쉽게 사용할 수있는 명백한 키워드가 없으므로 연산자를 신중하게 사용하는 경우가 있습니다. 그러나 너무 많지는 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.