2010-05-24 2 views
9

나는 다음과 같은 유형의 서명으로 함수가 있다고 가정 :사용 항목

g :: a -> a -> a -> b 

가 나는 또한 a의 목록이 나는 적어도 세 가지를 포함합니다 알 - 그래이 xs를 호출들-하자 항목. xs의 처음 세 항목에 g을 적용하고 싶습니다. 나는 다음과 같이 연결자를 정의 할 수 있습니다 알고

($$$) :: (a -> a -> a -> b) -> [a] -> b 
f $$$ (x:y:z:_) = f x y z 

그럼 난 그냥 g $$$ xs를 사용할 수 있습니다. 이렇게하면 $$$uncurry과 약간 비슷하지만, 동일한 유형의 인수가 세 개인 튜플 대신 목록에 사용됩니다.

표준 결합자를 사용하여이를 관용적으로 수행 할 수있는 방법이 있습니까? 아니면, 하스켈에서 이것을하는 가장 관용적 인 방법은 무엇입니까? $$$의 non-infix 버전에서 pointfree을 시도하면 어디서부터 시작해야할지 생각해 볼 수 있다고 생각했지만 출력은 headtailap 및 소수의 괄호가 소수 인 1flip과 약간 씩을 나타 냈습니다.

(NB : 처음에는 할 스케이프가 아니라는 것을 알고 있지만, Parsec을 사용할 때 합리적인 해결책 인 것처럼 보입니다. 확실히이 최선의 대답이 "이 실제 코드에서이 작업을 수행하지 않는다"동의하지만, 나는 ((->) r) 모나드 또는 무엇이든을 포함하는 일부 영리한 트릭을 볼 원합니다.) 제 생각이에서

+4

코드에 어떤 문제가 있는지 보지 않습니다. 그것은 짧고 중요한 것입니다. 모든 것이 (또는되어야한다) pointfree가 아니어야한다. – sepp2k

+1

필자는 거기에 아무 문제가 없다고 생각하지 않는다. $$$와 같은 새로운 연결자를 정의하지 않고도이를 수행 할 수있는 간결한 방법이 있는지 궁금하다. –

+0

이것은 부분적인 함수이므로, 일반적으로 나쁜 아이디어 일 것입니다 :) 당신은'($$$) :: (a -> a -> b) -> [a] -> 아마도 b' –

답변

12

또는 오히려, 하스켈에서이 작업을 수행 할 수있는 가장 관용적 인 방법은 무엇입니까?

관용구? ($$$)이하는 기능을 실제로 원한다면, 가지고있는 코드는 아마도 관용적 일 것입니다.

나는 이 경우에 일부 영리한 트릭

오,를 참조하기 원합니다.

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE OverlappingInstances #-} 
{-# LANGUAGE UndecidableInstances #-} 
class ListApply f a r | f -> a r where 
    ($...) :: f -> [a] -> r 

instance (TypeCast b r) => ListApply b a r where 
    x $... _ = typeCast x 

instance (ListApply f a r) => ListApply (a -> f) a r where 
    f $... (x:xs) = (f x) $... xs 

가 당신이 완전히 일반적인 솔루션 이동 : a -> a ... -> b 같은 서명을 임의의 인수에 대응하는 기능을 감안할를, 필요에 따라 목록 [a]의 많은 요소에 적용합니다.데모 : GHCi에서

ones :: [Int] 
ones = repeat 1 

test1 x = x 
test2 x y = x + y 
test3 x y z = (x + z) * (y + z) 

:

> test1 $... ones 
1 
> test2 $... ones 
2 
> test3 $... ones 
4 

내가 확실히 받아 들일 겁니다는 "지금까지 실제 코드에서이 작업을 수행하지 않는다"그게 가장 좋은 대답을인지

당신 아마 그걸로 가고 싶다.


아, 그리고 위의 코드를 실행하는 데 필요한 보일러의 비트 :

class TypeCast a b | a -> b, b->a where typeCast :: a -> b 
class TypeCast' t a b | t a -> b, t b -> a where typeCast' :: t->a->b 
class TypeCast'' t a b | t a -> b, t b -> a where typeCast'' :: t->a->b 
instance TypeCast' () a b => TypeCast a b where typeCast x = typeCast'() x 
instance TypeCast'' t a b => TypeCast' t a b where typeCast' = typeCast'' 
instance TypeCast''() a a where typeCast'' _ x = x 

이 유형 레벨 메타 프로그래밍, Oleg Kiselyov의 호의의 스위스 군용 칼입니다.

7
f $$$ (x:y:z:_) = f x y z 

을 가장 관용적이고 간결한 방식입니다. 인수의 수가 변하는 경우 템플릿 하스켈을 사용하거나 반복적으로 그것을 할 수 있습니다 - 정의 :

zero = const 
next n f (x:xs) = n (f x) xs 

다음 함수가 next (next (next zero)))이며,이 next의 중첩 작동합니다. 또한

당신이 더 원시적 인 콤비 그것을 깰 수

firstThree (x:y:z:_) = (x,y,z) 
uncurry3 f (x,y,z) = f x y z 
g f = uncurry3 f . firstThree 
관련 문제