有没有什么方法可以为任何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被评估一次,然后保持该值,即使确实起作用了,它仍然是丑陋的,黑客和通常是邪恶的。有没有办法做到这一点,或者我只能放弃这个想法?
发布于 2012-03-23 02:43:46
我是个新手,所以请原谅我这是一个愚蠢的答案,但这不正是应用函数器的用途吗?
应用程序可以让你做一些类似的事情:
f :: a -> b -> ... -> c
f2 :: Applicative p => p a -> p b ... -> p c
f2 x ... y = f <$> x <*> ... <*> y如果我没记错的话。(省略号是任意数量的类型/参数)
发布于 2012-03-23 02:58:14
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或其他monad (如sodium库中所示)。
https://stackoverflow.com/questions/9828401
复制相似问题