문제

유형과 같은 기능이있을 때

f :: (Ord a) => a -> a -> Bool
f a b = a > b

나는이 기능을 랩핑하지 않는 기능을 좋아해야합니다.

예를 들어, 이런 기능을합니다

g :: (Ord a) => a -> a -> Bool
g a b = not $ f a b

나는 콤바네이터를 좋아할 수 있습니다

n f = (\a -> \b -> not $ f a b)

그러나 나는 방법을 모른다.

*Main> let n f = (\a -> \b -> not $ f a b)
n :: (t -> t1 -> Bool) -> t -> t1 -> Bool
Main> :t n f
n f :: (Ord t) => t -> t -> Bool
*Main> let g = n f
g :: () -> () -> Bool

내가 뭘 잘못하고 있죠?

그리고 보너스 질문 더 많은 매개 변수로 기능을 위해이 작업을 수행 할 수있는 방법

t -> Bool
t -> t1 -> Bool
t -> t1 -> t2 -> Bool
t -> t1 -> t2 -> t3 -> Bool
도움이 되었습니까?

해결책

생각 실험과 개념 증명에 남은 타입 클래스로 해킹을 원하지 않는 한, 여러 인수를 일반화하지 않습니다. 시도하지 마십시오.

주요 질문은 Conal Elliott의 가장 우아하게 해결됩니다. 시맨틱 편집기 조합. 시맨틱 편집기 콤바이터는 다음과 같은 유형의 함수입니다.

(a -> b) -> F(a) -> F(b)

어디에 F(x) 관련된 표현입니다 x. 또한 (b -> a) 대신에. 직관적으로, 편집기 콤바이터는 작동 할 더 큰 값의 일부를 선택합니다. 당신이 필요한 것을 호출합니다 result:

result = (.)

작업하려는 표현의 유형을보십시오.

a -> a -> Bool

이 유형의 결과 (codomain)는 다음과 같습니다 a -> Bool, 그리고 결과 저것 유형입니다 Bool, 그리고 그것이 당신이 적용하려는 것입니다 not 에게. 그래서 신청합니다 not 함수 결과의 결과 f, 당신은 쓰기:

(result.result) not f

이것은 아름답게 일반화됩니다. 다음은 몇 가지 조합 자입니다.

argument = flip (.)     -- contravariant

first f (a,b) = (f a, b)
second f (a,b) = (a, f b)

left f (Left x) = Left (f x)
left f (Right x) = Right x
...

따라서 가치가 있다면 x 유형 :

Int -> Either (String -> (Int, Bool)) [Int]

그리고 당신은 신청하고 싶습니다 not Bool에게, 당신은 거기에 도착할 길을 철자합니다.

(result.left.result.second) not x

아, 그리고 당신이 아직 함유자를 얻었다면, 당신은 그것을 알게 될 것입니다 fmap 편집기 콤비네이터입니다. 실제로 위의 철자는 다음과 같습니다.

(fmap.left.fmap.fmap) not x

그러나 확장 된 이름을 사용하는 것이 더 명확하다고 생각합니다.

즐기다.

다른 팁

실제로, 유형 수업으로 임의의 아티브를하는 것은 매우 쉬운 것으로 판명됩니다.

module Pred where

class Predicate a where
  complement :: a -> a

instance Predicate Bool where
  complement = not

instance (Predicate b) => Predicate (a -> b) where
  complement f = \a -> complement (f a)  
  -- if you want to be mysterious, then
  -- complement = (complement .)
  -- also works

ge :: Ord a => a -> a -> Bool
ge = complement (<)

이 멋진 문제를 지적 해 주셔서 감사합니다. 나는 Haskell을 좋아합니다.

N 콤바이터는 다음을 작성할 수 있습니다.

n = ((not .) .)

보너스 질문은 일반적인 방법은 다음 중 몇 가지를 만드는 것입니다.

lift2 = (.).(.)
lift3 = (.).(.).(.)
lift4 = (.).(.).(.).(.)
lift5 = (.).(.).(.).(.).(.)

등.

답장: 내가 뭘 잘못하고 있죠?:

나는 당신의 빗질자가 괜찮다고 생각하지만, 당신이 최상위로 바꾸면 Haskell의 성가신 '기본 규칙'중 하나가 작동하며 바인딩은 일반화되지 않습니다.

Prelude> :ty (n f)
(n f) :: (Ord t) => t -> t -> Bool
Prelude> let g = n f
Prelude> :ty g
g :: () -> () -> Bool

나는 당신이 유형 클래스에 적용되는 '단일성 제한'에 의해 뭉개지고 있다고 생각합니다. 어쨌든, 최상위 루프에서 벗어나 명시 적 유형 서명이있는 별도의 파일에 물건을 넣으면 모두 잘 작동합니다.

module X where

n f = (\a -> \b -> not $ f a b)
f a b = a > b

g :: Ord a => a -> a -> Bool
g = n f

보너스 질문: 점점 더 많은 유형의 매개 변수 로이 작업을 수행하려면 유형 클래스 시스템으로 괴혈병 트릭을 재생할 수 있습니다. 상담해야 할 두 가지 논문은 휴즈와 클라 센스입니다 QuickCheck에 종이 그리고 Ralf Hinze의 논문 대중을위한 제네릭.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top