2010-12-02 5 views
19

가끔 "나는 마지막 인수를 두 번 사용하십시오."라고 표현하고 싶은 문제에 걸려 넘어집니다. pointfree 스타일을 작성하거나 람다를 피하기 위해. 예 :하스켈에서 "재사용"주장의 속임수?

sqr x = x * x 

sqr = doubleArgs (*) where 
    doubleArgs f x = f x x 

로 작성 또는 (this question에서 촬영)이 약간 더 복잡한 기능이 고려 될 수있다 : 같은 기능이 있다면

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs) 

나는이 코드 pointfree를 작성할 수를 이 :

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where 
    dup f f1 f2 x = f (f1 x) (f2 x) 

그러나 doubleArgs 나 dup 같은 것을 Hoogle에서 찾을 수 없으므로 여기서 트릭이나 관용구를 놓칠 수도 있습니다. 확장

join :: (Monad m) -> m (m a) -> m a 
join m = m >>= id 

instance Monad ((->) r) where 
    return = const 
    m >>= f = \x -> f (m x) x 

:

Control.Monad에서

답변

26

그래서
join :: (a -> a -> b) -> (a -> b) 
join f = f >>= id 
     = \x -> id (f x) x 
     = \x -> f x x 

, 그래, Control.Monad.join. 아, 그리고 당신의 pointfree의 예를 들어

, 당신은 (Control.Applicative에서) 실용적 표기법을 사용하여 시도가 : 사람들이 a ++ (x:b) 대신 a ++ [x] ++ b 너무 좋아하는 이유

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails 

(I도 모르는 ... 오케이)

+2

그리고'pointfree'에 따르면,'dup'은'liftM2'로 작동합니다.함수에 대한 모나드 인스턴스를보다 잘 처리 할 필요가 있습니다. –

+2

이러한 문제를 해결하기 위해 ** 두 가지 방법을 사용해 주셔서 감사합니다. BTW 나는'sqr = (*) id'을 시도했고 그것은 잘 작동한다 :-) – Landei

+0

'a ++ (x : b)'는 다른 것보다 3 글자 더 짧다. –

11

'doubleArgs'라고 불리는 것이 더 자주 dup이라고 불리는데, 이것은 W 결합 자입니다 ('warbler'라고 부름). Mockingbird를 모의하기) - "기본 복제기".

'dup'이라고하는 것은 실제로 '별 모양의'조합입니다.

하스켈은 Data.Function과 몇 가지 Applicative 및 Monadic 연산에 더하여 Applicative 및 Monad (< *)의 함수 인스턴스를 통해 더 많은 "표준"결합자를 추가합니다. Applicative는 S - 기능 인스턴스에 starling 결합 자, liftA2 & liftM2가 starling-prime입니다. Data.Function을 확장하기 위해 커뮤니티에서 많은 열의가있는 것처럼 보이지는 않습니다. 그래야 결합자가 재미 있고 실용적으로 결합자를 직접 사용할 수없는 상황에서 장거리를 선호하게되었습니다.

+2

아, 하스켈의 "새 연산자"를 발견했습니다. http://hackage.haskell.org/packages/archive/data-aviary/0.2.3/doc/html/Data-Aviary-Birds.html – Landei

+2

@Landei - 나는 그것들을 "참조 용"으로 간주한다. 즉, 작업 코드에 의존하지 않는 것이 좋다. 나는 Cabal 설명을 그들이 "참조 용"이라고 더 분명하게해야한다. 그러나 나는 아직 그것에 대해 알지 못했다. –

+2

@ Landei가'dup'을 호출하는 것은 연산자 [j의 "동사 포크"] (http://www.jsoftware.com/help/jslc/forks_hooks_and_compound_adv.htm)로도 알려져 있으며, 연산자의 간단한 병 렬에 의해 작성됩니다. 예 '(f g h) x' 대신'dup f g h x'를 사용한다. –

7

여기 내 질문의 두 번째 부분에 대한 또 다른 해결책 : 화살표!

import Control.Arrow 

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++)) 

&&& ("팬 아웃")는 두 가지 기능의 인자를 분배하고 결과의 쌍을 반환한다. >>> ("and then")은 왼쪽에서 오른쪽으로 작업 체인을 가질 수있는 함수 적용 순서를 바꿉니다. second은 쌍의 두 번째 부분에서만 작동합니다. 물론 두 개의 인수를 기대하는 함수에서 쌍을 공급하려면 끝에 uncurry이 필요합니다.