'zip'이 컬렉션의 매달려있는 꼬리를 무시하는 이유는 무엇입니까?


12

C # , Scala, Haskell, Lisp 및 Pythonzip동작 은 동일 합니다. 하나의 컬렉션이 더 길면 꼬리는 자동으로 무시됩니다.

예외도 발생할 수 있지만이 방법을 사용하는 언어에 대해서는 들어 보지 못했습니다.

이것은 나를 퍼즐. 왜 그렇게 zip설계된 이유를 아는 사람이 있습니까? 나는 다른 언어가 이런 식으로하기 때문에 새로운 언어를 생각합니다. 근본 원인은 무엇입니까?

나는 누군가가 그것을 좋아하는지, 또는 그것이 좋은지 나쁜지가 아니라 사실적이고 역사적인 기반의 질문을하고 있습니다.

업데이트 : 내가 무엇을 해야하는지 묻는다면, 배열을 인덱싱하는 것과 비슷하게 예외를 던집니다 ( "오래된"언어는 모든 종류의 마술을 했음에도 불구하고 범위, 인덱스, UB, 확장 배열을 처리하는 방법, 기타).


10
하나의 functor가 가진 꼬리를 무시하지 않으면 무한 시퀀스를 사용하는 것이 더 번거로울 것입니다. 특히 무한대 범위의 길이를 얻는 것이 비싸거나 복잡하거나 불가능한 경우.
중복 제거기

2
당신은 이것이 예상치 못한 이상한 것이라고 생각하는 것 같습니다. 나는 그것이 명백하고 실제로 불가피하다는 것을 안다. 어떤 것이 당신은 당신이 동일하지 않은 길이의 컬렉션을 압축 할 때 일어날까요?
Kilian Foth

@KilianFoth, 예외가 발생합니다.
greenoldman

@ 중복 제거기, 좋은 하나. 조용한 꼬리 하락으로 zipWithIndex자연수 생성기를 자연스럽게 표현할 수 있습니다 . 이제 정보의 유일한 누락 된 부분은 - 무엇 이었습니까 이유? :-) (btw. 답변으로 의견을 다시 게시하십시오. 감사합니다).
greenoldman

1
파이썬에는 itertools.izip_longest가 있는데, 이는 None으로 완성 된 입력을 자동으로 채 웁니다. 실제로 zip을 사용할 때 zip보다 자주 선택합니다. 그래도 더 이상 선택의 이유를 기억할 수 없습니다. 파이썬은 이미 @greenoldman의 경우에 대해 enumerate ()를 가지고 있습니다.
StarWeaver

답변:


11

그것은 거의 항상 당신이 원하는 것입니다. 그렇지 않을 때는 직접 채울 수 있습니다.

가장 큰 문제는를 처음 시작할 때 길이를 모르는 게으른 의미론으로 시작시 zip예외를 던질 수 없습니다. 먼저 모든 공통 요소를 반환 한 다음 예외 throw해야합니다. 매우 유용하지는 않습니다.

스타일 문제이기도합니다. 명령형 프로그래머는 모든 곳에서 경계 조건을 수동으로 확인하는 데 익숙합니다. 기능 프로그래머는 설계 상으로는 실패 할 수없는 구조를 선호합니다. 예외는 매우 드 rare니다. 함수가 합리적인 기본값을 반환하는 방법이 있다면, 함수형 프로그래머가이를 취할 것입니다. 작곡은 왕입니다.


내가 할 수있는 것이 아니라 역사적인 이유에 대해 묻고 있습니다. 두 번째 단락-당신은 틀 렸습니다 zip. 현재 어떻게 구현되어 있는지 살펴보십시오 . 예외를 던지는 것은 단순히 "stop yield"를 "throw"로 바꾸는 것입니다. 세 번째 단락-경계를 벗어난 빈 요소를 반환하는 것은 실패 할 수 없지만 FP 개발자가 좋은 디자인이라고 투표하지는 않습니다.
greenoldman

3
두 번째 단락은 모든 구현에 적용되는 것이 아니라 진정 게으른 것에 만 적용됩니다. zip두 개의 무한 시퀀스가 ​​함께 있으면 시작 크기를 알 수 없습니다. 세 번째 단락에서 나는 합리적인 불이행을 말했다 . 이 경우 비워 두는 것은 합리적이지 않지만 꼬리를 떨어 뜨리는 것은 분명합니다.
Karl Bielefeldt

아, 나는 당신의 요점을 마지막으로 본다. 게으른 언어로 예외를 던지면 기술 대체가 아니며, 처음에는 예외를 던져야하기 때문에 행동의 변화입니다. 편리 할 때마다 꼬리를 무시할 수 있습니다.
greenoldman

3
+1 이것은 또한 "기능적 프로그래머는 설계에 의해 실패 할 수없는 구조를 선호한다"는 훌륭한 해답이다. 이것은 기능 프로그래머가 결정하는 대부분의 설계 결정에있어 가장 큰 동기가 무엇인지를 설득력있게 말한다. 명령형 프로그래머는 "말하고 묻지 말아라"라는 규칙을 좋아합니다. FP는 절대 마지막 순간까지 결과를 확인하지 않고도 명령을 지속적으로 알려주는 데 중점을 두어이를 N 번째 수준으로 끌어 올립니다. 따라서 중간 단계를 보장하려고합니다. Composability가 왕이기 때문에 실패 할 수 없습니다 . 아주 잘 말했다.
Jimmy Hoffa

12

꼬리를 완성하는 확실한 방법이 없기 때문입니다. 이를 수행하는 방법을 선택하면 명확하지 않은 꼬리가 생깁니다.

트릭은 가장 긴 목록의 길이를 예상 한 값과 일치하도록 가장 짧은 목록을 명시 적으로 늘리는 것입니다.

만약 zip이 당신을 위해 그렇게한다면, 당신은 그것이 어떤 값을 직관적으로 채우고 있는지 알 수 없었습니다. 목록을 순환 했습니까? 빈 값을 반복 했습니까? 귀하의 유형에 대한 빈 값은 무엇입니까?

꼬리가 길어지는 방식을 직관하는 데 사용할 수있는 지퍼의 기능에는 영향이 없으므로 소비자가 기대하지 못할 수도있는 값을 사용하는 것이 합리적입니다.


또한 잘 알려진 특정 의미론을 가진 매우 특정한 잘 알려진 함수를 참조하고 있음을 기억하십시오. 그렇다고해서 유사하지만 약간 다른 기능을 수행 할 수는 없습니다 . 을 수행하는 공통 기능이 있다고 x해서 원하는 목표 x와 목적을 결정할 수 없다는 의미는 아닙니다 y.

이것과 다른 많은 일반적인 FP 스타일 함수가 일반적인 이유를 기억하지만, 간단하고 일반화되어 있기 때문에 코드를 사용하여 원하는 동작을 수행 할 수 있습니다. 예를 들어 C #에서는

IEnumerable<Tuple<T, U>> ZipDefaults(IEnumerable<T> first, IEnumerable<U> second)
{
    return first.Count() < second.Count()
        ? first.Concat(Enumerable.Repeat(default(T), second.Count() - first.Count())).Zip(second)
        : first.Zip(second.Concat(Enumerable.Repeat(default(U), first.Count() - second.count())))
}

또는 다른 간단한 것들. FP 접근 방식을 사용하면 조각을 재사용 할 수있을뿐 아니라 구현이 너무 작아서 자신 만의 수정 된 버전을 만드는 것이 매우 간단하기 때문에 수정이 매우 쉽습니다.


좋아,하지만 컬렉션이 다른 것과 일치하는 것을 강제로 할 때만-컬렉션 인덱싱 (배열)과 비교하십시오. 범위를 벗어난 인덱스가 있으면 확장하고 배열해야한다고 생각할 수 있습니까? 또는 요청을 자동으로 무시할 수 있습니다. 그러나 얼마 동안 예외를 던지는 일반적인 개념이 있습니다. 일치하는 컬렉션이 없으면 예외를 throw하십시오. 왜이 방법을 사용하지 않았습니까?
greenoldman

2
zipnull을 채울 수 있으며 이는 종종 직관적 인 솔루션입니다. 유형을 고려하십시오 zip :: [a] -> [b] -> [(Maybe a, Maybe b)]. 물론 결과 유형은 약간 비현실적이지만 그 위에 다른 동작 (바로 가기, 예외)을 쉽게 구현할 수 있습니다.
amon

1
@ amon : 그것은 전혀 직관적이지 않습니다, 그것은 바보입니다. 모든 인수를 검사하는 null이 필요합니다.
DeadMG

4
@amon 모든 유형에 null이있는 것은 아닙니다. 즉 mempty, 객체는 공간을 채우기 위해 null이 있지만 int 및 기타 유형에 대해서도 그러한 것을 생각해 내고 싶습니까? 물론 C #은 default(T)모든 언어를 지원하는 것은 아니며 C #조차도 그 행동 이 명백 합니까? 나는 그렇게 생각하지 않는다
Jimmy Hoffa

1
@amon 아마도 더 긴 목록의 소비되지 않은 부분을 반환하는 것이 더 유용 할 것입니다. 이를 사용하여 필요한 경우 실제 길이가 같은지 확인하고 목록을 다시 탐색하지 않고 소비되지 않은 꼬리로 무언가를 다시 압축하거나 수행 할 수 있습니다.
Doval
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.