2014-08-31 2 views
6

파이썬에서 lst * count과 같은 시간 계산 횟수를 더한 목록을 반환하는 하스켈 함수를 작성하고 싶습니다.Pointfree 버전은 컴파일되지 않지만 유의미한 버전은 컴파일합니까?

self_append_n :: Int -> [a] -> [a] 
self_append_n = concat . replicate 

내 추론 replicate는 카운트와 값을 받아들이는이고, 값의리스트를 생성한다 :

내 최초의 시도이다. 값 자체가리스트 일 때, 나머지리스트는리스트를 연결하는 것입니다. 그러나,이 어지러 울 오류가 있습니다 :

Couldn't match type `[a0]' with `[a] -> [a]' 
Expected type: [[a0]] -> [a] -> [a] 
    Actual type: [[a0]] -> [a0] 
In the first argument of `(.)', namely `concat' 
In the expression: concat . replicate 
In an equation for `self_append_n': 
    self_append_n = concat . replicate 

그런 다음 나는 pointful 버전 썼다 :

self_append_n a b = concat $ replicate a b 

을하고 작동!

왜 포인트 프리 버전은 컴파일되지 않지만 점을 추가하면 작동하지 않습니까?

답변

11

그것은 아마 명시 적으로 서명을 parenthesise하는 데 도움이 : 당신이 concat . replicate을 구성하려고하면

selfAppend :: Int -> ([a]   -> [a]) 
replicate :: Int -> ([a]->[[a]]) 
concat  ::   [[a]]  -> [a] 

, 당신은 즉 [a] -> [[a]], replicateconcat 부분적으로 appied 결과를주고 끝낸다. 이는 [[a]]과 통합되지 않습니다.

당신이해야 할 일은 모두 인수를 replicate에 전달한 후 결과를 전달하는 것입니다. IMO 그 작업을 수행하는 가장 좋은 방법은 "반 pointfree"입니다 :

selfAppend n = concat . replicate n 

적은 읽을 수있는 대안이

selfAppend' = curry $ concat . uncurry replicate 
selfAppend'' = (concat.) . replicate 

을 것 또는 악명 높은 연산자

(.:) :: (c->d) -> (a->b->c) -> a->b->d 
(.:) = (.).(.) 
-- `≡ fmap fmap fmap`, also a popular implementation... 

단순히

을 쓸 수 있습니다
selfAppend''' = concat .: replicate 
+4

알겠습니다. 복제의 실제 반환 유형이 목록이 아니고 함수 (자체가 목록을 반환)이기 때문에 구성이 실패합니다. –

+1

예. 불행히도 하스켈의 모든 철학은 항상 이득이되는 것은 아니지만 (매우 자주 있지만). – leftaroundabout