【发布时间】:2012-04-07 09:00:53
【问题描述】:
有没有办法为任何n编写函数f :: (a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t),基本上是liftMn?
(编辑:固定无意义的例子。)
我正在编写一个 FRP 库,并认为如果我可以有类似这样的代码会很整洁:
main = do
input1 <- signalFromTextBoxTheUserMayTypeANumberInto
input2 <- signalFromAnotherTextBox
divided <- signal div input1 input2
signal (\x -> showTextAlert ("input1 `div` input2 is " ++ show x)) divided
我一直在摆弄类型族以使其正常工作,但我开始认为这实际上是不可行的。我目前正在做这样的事情:
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 =
\s@(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
这显然是行不通的,因为 unsafePerformIO 被评估一次,然后保持该值,如果确实有效,它仍然是丑陋的,hacky 并且通常是邪恶的。有没有办法做到这一点,还是我只能放弃这个想法?
【问题讨论】:
-
问问你自己:我能给这个组合器一个合理的类型吗?如果不是,需要什么样的黑魔法才能让它有一个合理的类型?这可能会有所帮助:How to create a polyvariadic haskell function?
标签: haskell types monads type-families