this answer on CodeReview에서 asker와 answerer는 (++) 연산자에 대해 경멸감을 보입니다. 이것은 속도 때문입니다 (알고리즘을 O (n^2)에서 명시 적으로 실행시키는 원인이됩니까? n은 목록 iirc의 길이입니다)? Haskell이 시간 복잡성에 대해 추론하기 어렵다는 것이 알려져 있기 때문에 다른 테스트를 거치지 않았다면 이것은 사전 최적화입니까? 다른 사람들이 프로그램에서 (++) 연산자를 사용하지 않아야합니까?하스켈에서 ++ 피하기
답변
에 따라 다릅니다.
이 표현식은 하나의리스트에리스트 목록을 연결하지만, 상기 이차 복잡도를 갖는 표현식을
foldl (++) [] list
을 고려한다. 이것은 (++)
의 구현이 전체 왼쪽 목록을 가로 지르고 올바른 순서로 각 요소를 오른쪽 목록 앞에 추가하기 때문에 발생합니다.
foldr (++) [] list
이는 왼쪽 인자를 통과하고 오른쪽으로 앞에 추가 (++)
운영자의 구현에 기인한다 : 오른쪽 배를 사용
, 우리는 선형 복잡도를 얻을.
[1,2] ++ [3,4] ++ [5,6]
번만 각리스트 요소를 통과
-- Example as created by foldr
[1,2] ++ ([3,4] ++ [5,6])
== [1,2] ++ [3,4,5,6]
== [1,2,3,4,5,6] -- all good, no element traversed more than once
같다.
이제 괄호를 처음 두 목록으로 전환하는 것이 더 비쌉니다. 이제 일부 요소가 여러 번 통과하기 때문에 비효율적입니다.
-- Example as created by foldl
([1,2] ++ [3,4]) ++ [5,6]
== [1,2,3,4] ++ [5,6]
== [1,2,3,4,5,6] -- the sublist [1,2] was traversed twice due to the ordering of the appends
이러한 경우에는주의해야합니다.
foldl이 항상 왼쪽 연관 연산자와 함께 사용되도록 일반화 할 수 있습니까? 우리가 foldl로 무엇을합니까? 편집 : 작업이 왼쪽과 오른쪽 모두 연관되어 있으면 foldl을 의미합니까
@JackBrandt 아니요, 적어도 일반적인 규칙은 아닙니다. '(^)'(또는'(-)')를 상상해보십시오.이 연산자는 왼쪽과 오른쪽 접힌 상태에서 각각 다른 결과를냅니다. 그것은 당신이 원하는 것을 따라 달라집니다. 'foldl '은 완전히 다른 문제입니다. 표준의 엄격한 버전 인'foldl'이며, 명시 적으로 썽크를 만들고 싶을 때를 제외하고는'foldl'보다 거의 항상 선호되어야합니다. – ThreeFx
누군가가 썽크를 키우고 싶은 이유를 확장 할 수 있습니까? 대중적인 이해에 오히려 직관력이없는 것처럼 보입니다. 또한, 수학적 예제는 실제로 b/t 폴드의 차이를 이해하는 데 매우 유용했습니다. –
- 1. 하스켈에서 "재사용"주장의 속임수?
- 2. 하스켈에서 읽기
- 3. 하스켈에서 인쇄
- 4. 중첩지도 하스켈에서
- 5. 하스켈에서 Scanl
- 6. 하스켈에서 함께
- 7. 하스켈에서 Clojure로
- 8. 하스켈에서 생성자
- 9. 하스켈에서 자바
- 10. 매핑! 하스켈에서
- 11. 하스켈에서 주조
- 12. 하스켈에서 "fold"?
- 13. 하스켈에서 대용량 파일 다루기
- 14. 하스켈에서 클로저와리스트 해설
- 15. 하스켈에서 자바 스크립트 컴파일러로?
- 16. 하스켈에서 네트워크 인터페이스 나열
- 17. 하스켈에서 타입 간의 변환
- 18. spanM, 하스켈에서 takeWhileM
- 19. 하스켈에서 목록리스트로 쇼 사용하기
- 20. 하스켈에서 그래프 편집/업데이트
- 21. 하스켈에서 매개 변수가있는 함수
- 22. 하스켈에서 연산자 우선 순위
- 23. 제대로 하스켈에서 F 번호
- 24. 하스켈에서 (: =) 의미는 무엇입니까?
- 25. 하스켈에서 점 (.)이 어떻게됩니까?
- 26. 하스켈에서 큰 따옴표 인쇄하기
- 27. 하스켈에서 어떻게 폐쇄가 작동합니까?
- 28. 하스켈에서 이벤트 오버라이드
- 29. 하스켈에서 프로그램의 적합성을 확인하십시오
- 30. 하스켈에서 변경 불가능한 세트
하스켈 목록은 링크 된 목록이고 추가 목록은 엄격한 언어의 O (* n *) 연산입니다. 그러나 Haskell에서는 게으름으로 목록이 사용될 때까지 작업을 연기 할 수 있으므로 목록의 길이에 걸쳐 효과적으로 비용을 분배 할 수 있습니다. 이 게으름은 하스켈에서 시간과 공간의 복잡성을 설명하기 어렵게 만들지 만, 다른 언어에 대한 동일한 조언이 하스켈에도 적용된다고 생각합니다. 먼저 명확성을 기하고, 둘 모두가 필요한 경우에만 속도를 최적화하십시오. 더 빨리 갈 수 있습니다 * 그리고 * 병목 현상을 발견하기 위해 프로파일 링했습니다. –
두 가지 모두 있습니다. 코드에 대해 추론하기가 더 어려워지며 대개 코드가 느려지고 사용하는 경우가 많습니다. 그러나 모든 상황과 IMO에 따라 다릅니다. SO – Carsten
@Carsten : 나는 보통 "당신의 코드 속도가 느려진다"라는 당신의 말에 약간 혼란 스럽다. 이것은 정규 tail-recursive 계승의 예에서 분명히 사실이지만, 이것은 일상적인 프로그램에서 실제로 아주 흔한 일입니까? 루비 (Ruby) 나 파이썬 (Python)과 같이 널리 사용되는 외부인 언어 중 하나를 사용하는 하스켈 (Haskell)과 같은 이점이 풍부한 타이핑 시스템에 의해 제공되는 최적화라고 생각했습니다. 정말로 내 질문이 구체적이지 않다고 생각하는 경우, 제공된 예에서 마지막 질문 만 저장하면됩니다 (이는 내 의도 였고 ThreeFx가 알아 냈다고 생각합니다.) –