2012-09-27 2 views
5

나는 두 개의 인자 (x와 y)를 가진 세 개의 함수 (getRow, getColumn, getBlock)를 가지고 있으며, 각각은 같은 타입의리스트를 생성한다. 나는 그들의 출력을 연결합니다 네 번째 함수를 작성하려면 :하스켈의 여러 인수를 통해 함수 목록을 매핑하는 방법은 무엇입니까?

outputList :: Int -> Int -> [Maybe Int] 
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

기능은 작동을하지만, 이중지도를 재 작성하는 방법이 하나의지도에 (세 '$'의 포함)이 있습니까?

답변

22
import Data.Monoid 

outputList :: Int -> Int -> [Maybe Int] 
outputList = mconcat [getRow, getColumn, getBlock] 

당신은 설명을 가치가있다.

먼저 모든 함수의 유형이 동일하다는 점을 분명히 설명합니다.

outputList, getRow, getColumn, getBlock :: Int -> Int -> [Maybe Int] 

이제 원래의 정의부터 살펴 보겠습니다.

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

이러한 함수의 결과는 [Maybe Int]이며, 모든 항목의 목록은 모노로이드입니다. 목록을 단수로 결합하는 것은 목록을 연결하는 것과 동일하므로 concatmconcat으로 바꿀 수 있습니다.

outputList x y = mconcat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

monoid 인 또 다른 것은 결과가 monoid 인 경우 함수입니다. 다시 말하면, b이 monoid이면, a -> b도 monoid입니다. 함수를 단수로 결합하는 것은 동일한 매개 변수로 함수를 호출 한 다음 결과를 단수적으로 결합하는 것과 같습니다.

그래서 우리는

outputList = mconcat [getRow,getColumn,getBlock] 

우리는 완료에 다시 다음

outputList x = mconcat $ map ($ x) [getRow,getColumn,getBlock] 

을 단순화하고 있습니다! 이 경우 잘 모르겠습니다 있지만 Typeclassopedia has a section about monoids


, 그것은 documentation for Data.Monoid 넘어 그 정도를 추가합니다.

4

는 첫 단계로, 우리는 정의

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

다음과 같이 함수의 합성 오퍼레이터 (.) 대신 함수 애플리케이션 ($) 연산자를 사용하여 재기록 될 수 있다는 것을 관찰한다.

outputList x y = (concat . map ($ y) . map ($ x)) [getRow,getColumn,getBlock] 

다음으로 우리는 map 다른 이름이 목록에 fmap위한 것이며 fmap 법칙을 만족하므로, 특히, 우리가 map (f . g) == map f . map g을 알 수 있습니다. 우리는이 법을 적용하여 map이라는 단일 응용 프로그램을 사용하여 버전을 정의합니다.

outputList x y = (concat . map (($ y) . ($ x))) [getRow,getColumn,getBlock] 

최종 단계로서 우리 concatMap 의해 concatmap과의 조성물을 대체 할 수있다.하스켈 프로그래머는 많은 공상 연산자를 사용하는 경향이 있지만

outputList x y = concatMap (($ y) . ($ x)) [getRow,getColumn,getBlock] 

마지막으로, 내 의견으로는, 함수의 기능이 명확하게 표현으로

outputList x y = concatMap (\f -> f x y) [getRow,getColumn,getBlock] 

에 의해 기능을 정의하는 수치가 아닙니다. 그러나 형식 클래스 추상화를 사용하면 (다른 대답에서 설명 된 것처럼) 문제가 특정 추상 구조를 가지며 새로운 통찰력을 얻는 것을 관찰 할 수 있으므로 좋은 방법이 될 수 있습니다.

2

가장 간결하고 정확하게 무엇을 의미하는지 표현하기 때문에 @ dave4420의 대답과 함께 갈 것입니다.

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

퓨즈 두지도 :

outputList x y = concat . map (($y) . ($x)) [getRow,getColumn,getBlock] 

교체 concatMapconcat . map :

당신이 Data.Monoid에 의존하고 싶지 않은 경우

기존 코드를 다음과 같이 그러나, 당신은 다시 쓸 수있다

outputList x y = concatMap (($y) . ($x)) [getRow,getColumn,getBlock] 

이제 끝났습니다.

편집 : aaaa 이것은 @Jan Christiansen의 대답과 정확히 같습니다. 오 잘!

+0

그런데 하스켈에 관한 질문에 대한 답변이있을 때까지 얼마나 오랜 시간이 걸립니까? 나는 하스켈의 모든 질문 중 90 퍼센트가 거의 즉각적으로 대답된다고 생각합니다. 이 답변의 품질에 대해 아무 말도하지 않지만, 내 생각에 그들은 꽤 높은 품질을 가지고 있습니다. –

+2

@JanChristiansen : 원하는 경우 스택 교환 데이터 탐색기를 사용하여 대답 할 수 있습니다. 나는 대략적인 근사치 (명백한 특이점 필터링, 자체 응답 무시, & c)를 수행했으며, 첫 번째 응답이 게시 될 때까지의 평균 (즉, 중앙값) 시간은 약 20 분이었습니다. –

관련 문제