2012-03-22 2 views
2

함수를 작성하는 몇 가지 방법이 있습니까 f :: (a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t), 어떤 n에 대해 기본적으로 liftMn?함수 작성 (a -> b -> ... -> t) -> (모나드 m => ma -> mb -> ... -> mt)

(편집 : 고정 무의미한 예.)

내가 FRP 라이브러리를 쓰고 있어요, 나는 막연하게 같은 코드가 수 있다면 깔끔한 줄 알았는데 :

main = do 
    input1 <- signalFromTextBoxTheUserMayTypeANumberInto 
    input2 <- signalFromAnotherTextBox 
    divided <- signal div input1 input2 
    signal (\x -> showTextAlert ("input1 `div` input2 is " ++ show x)) divided 

봤는데을 타입 패밀리를 사기 위해 노력했지만, 실제로는 할 수 없다고 생각하기 시작했습니다. unsafePerformIO 한 번 평가됩니다로서, 이것은 분명히 작동하지 않습니다

type Action a = IORef a -> IO() 
type Listener = IO() 
newtype Signal a = Signal (IORef (SigData a)) 

data SigData a = SigData { 
    trigger :: Action a, 
    output :: IORef a, 
    listeners :: [Listener] 
    } 

class Sig a where 
    type S a 
    mkSig :: [AnySignal] -> a -> S a 

instance Sig b => Sig (a -> b) where 
    type S (a -> b) = Signal a -> S b 
    mkSig dependencies f = 
    \[email protected](Signal sig) -> 
     let x = unsafePerformIO $ readIORef sig >>= readIORef . output 
     in mkSig (AnySignal s : dependencies) (f x) 

instance Sig Int where 
    type S Int = IO (Signal Int) 
    out <- newIORef x 
    self <- Signal <$> (newIORef $ SigData { 
     trigger = \ref -> writeIORef ref $! x, 
     output = out, 
     listeners = [] 
    }) 
    mapM_ (self `listensTo`) deps 
    return self 

을하고, 그 다음에 그 값을 유지하고 작업 않은 경우 여전히 못생긴 해키 일반적으로 나쁜 것 : 나는 현재 같은 일을하고 있어요 . 이것을 할 수있는 방법이 있습니까, 아니면 그냥 그 아이디어를 놓아 줘야할까요?

+0

자신에게 물어보십시오 :이 조합기를 적절한 유형으로 제공 할 수 있습니까? 그렇지 않다면 합리적인 유형으로 만들기 위해 어떤 종류의 까만 마술이 필요한가요? 이 도움이 될 수 있습니다 : [polyvariadic haskell 함수를 만드는 방법?] (http://stackoverflow.com/q/3467279/417501) – fuz

답변

10

저는이 모든 것을 처음 접했기 때문에 어리석은 대답이라면 저에게 용서해주십시오. 그렇지만 응용 펑터는 정확히 무엇이 아닌가? 내가 잘못 아니에요 경우

f :: a -> b -> ... -> c 

f2 :: Applicative p => p a -> p b ... -> p c 
f2 x ... y = f <$> x <*> ... <*> y 

:

Applicatives 당신이 뭔가를 할 수 있습니다. (줄임표는 여러 유형/인수입니다.)

+1

실제로. 주어진 예는'<- div <$> input1 <*> input2'으로 나눌 수 있습니다. 적용 펑터는 FRP에 이상적입니다. [reactive-banana] (http://hackage.haskell.org/package/reactive-banana) 및 [sodium] (http://hackage.haskell.org/package/sodium) 라이브러리가이 접근 방법을 취합니다. – ehird

+0

예,이 유형의 작업을 속임수로 쓸 수 없다면 백업 계획입니다. 그것은 꽤 아니지만. : – valderman

+2

@valderman, 유형 속임수는 문제를 일으키기 만합니다. 여러 번 수행되었으며, 가장 구체적인 경우를 제외하고는 모두 실패합니다 (즉, 추상화 능력을 파괴합니다). 나는 그들을 추천한다. (그리고 대수 구조에 대한 느낌을 얻으면 제안한 것보다 더 귀엽다고 느낄 것이다.) – luqui

6

적용 가능한 펑터에 대해 원래 표기 인 idiom brackets을 사용할 수있는 Strathclyde Haskell Environment 사전 처리기는 어떻습니까? 이를 통해 f <$> a <*> b <*> c(| f a b c |)을 사용할 수 있습니다. 귀하의 예는 (| input1 `div` input2 |)입니다.

그런데 Signal 유형이 Monad 인스턴스를 갖고있는 것은 좋지 않은 생각입니다. 이로 인해 잘 알려진 (FRP 커뮤니티에서) 시간 누수 문제가 발생합니다.; 자세한 내용은 this blog post을 참조하십시오. Applicative 인터페이스는 정상이지만 Monad 인터페이스는 아닙니다. an additional type parameter 또는 다른 모나드 (예 : sodium 라이브러리)와 같은 동적 이벤트 스위칭 동작을 허용하면서 시간 누설을 방지하는 몇 가지 솔루션이 있습니다.

+0

실제로는 _ <*> 어디서든 개선 된 표기가 될 것이다. Monad 인스턴스! – valderman

관련 문제