val*_*man 2 monads haskell types type-families
有没有办法写一个函数f :: (a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t),基本上是liftMn为了任何一个n?
(编辑:修复荒谬的例子.)
我正在写一个FRP库,并认为如果我的代码含糊不清,它会很整洁:
main = do
input1 <- signalFromTextBoxTheUserMayTypeANumberInto
input2 <- signalFromAnotherTextBox
divided <- signal div input1 input2
signal (\x -> showTextAlert ("input1 `div` input2 is " ++ show x)) divided
Run Code Online (Sandbox Code Playgroud)
我一直在摆弄类型系列以使它工作,但我开始认为它实际上是不可行的.我现在正在做这样的事情:
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
Run Code Online (Sandbox Code Playgroud)
这显然不起作用,因为unsafePerformIO被评估一次然后保持该值,如果确实有效,它仍然是丑陋,hacky和一般邪恶.有办法做到这一点,还是我必须放弃这个想法?
Geo*_*ton 10
我对这一切都很陌生,所以如果这是一个愚蠢的答案,请原谅我,但这不是应用函子的用途吗?
Applicatives让你做一些事情:
f :: a -> b -> ... -> c
f2 :: Applicative p => p a -> p b ... -> p c
f2 x ... y = f <$> x <*> ... <*> y
Run Code Online (Sandbox Code Playgroud)
如果我没错的话.(省略号是任意数量的类型/参数)
如何使用Strathclyde Haskell Environment预处理器,它可以让你使用成语括号,这是应用函子的原始符号吗?这允许您使用(| f a b c |)的f <$> a <*> b <*> c.你的例子就是(| input1 `div` input2 |).
顺便说一句,你的Signal类型有一个Monad实例可能是一个坏主意; 这导致了众所周知的(在FRP社区中)时间泄漏的问题; 有关更多信息,请参阅此博客文章.一个Applicative接口是OK,但Monad界面是不是.有几种解决方案可以防止时间泄漏,同时仍允许相同的动态事件切换行为,包括其他类型参数或其他monad(如钠库中所见).