首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >编写函数(a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t)

编写函数(a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t)
EN

Stack Overflow用户
提问于 2012-03-23 02:34:35
回答 2查看 226关注 0票数 2

有没有什么方法可以为任何n编写一个函数f :: (a -> b -> ... -> t) -> (Monad m => m a -> m b -> ... -> m t),基本上就是liftMn

(编辑:修复无意义示例。)

我正在写一个FRP库,我想如果我的代码大概是这样的话会很整洁:

代码语言:javascript
复制
main = do
  input1 <- signalFromTextBoxTheUserMayTypeANumberInto
  input2 <- signalFromAnotherTextBox
  divided <- signal div input1 input2
  signal (\x -> showTextAlert ("input1 `div` input2 is " ++ show x)) divided

我一直在摆弄类型家庭来让它工作,但我开始认为它实际上是不可行的。我目前正在做这样的事情:

代码语言:javascript
复制
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被评估一次,然后保持该值,即使确实起作用了,它仍然是丑陋的,黑客和通常是邪恶的。有没有办法做到这一点,或者我只能放弃这个想法?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-23 02:43:46

我是个新手,所以请原谅我这是一个愚蠢的答案,但这不正是应用函数器的用途吗?

应用程序可以让你做一些类似的事情:

代码语言:javascript
复制
f :: a -> b -> ... -> c

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

如果我没记错的话。(省略号是任意数量的类型/参数)

票数 10
EN

Stack Overflow用户

发布于 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 postApplicative接口可以,但Monad接口不行。有几种解决方案可以防止时间泄漏,同时仍然允许相同的动态事件切换行为,涉及an additional type parameter或其他monad (如sodium库中所示)。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9828401

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档