3

我正在对用于 UI 的 FRP 的实际方面进行一些研究,并且一直在努力使用响应式香蕉来实现以下功能:根据选择框的值,呈现可变数量的列表框,这些列表框会显示一些结果。(我正在使用 WxHaskell。)

使用一堆准备好的列表框来实现这一点非常简单,这些列表框根据结果行为隐藏和显示,但这次我希望它根据需要创建和销毁列表框,每个列表框都链接到结果行为。

到目前为止,我有以下成分:

  • eParam绑定到选择框的事件
  • 用(and )bResults :: Behavior t [[String]]定义的行为,它包含所有结果(每个列表框的项目列表)eParamstepper
  • 一个更新函数updateResultControls :: [SingleListBox ()] -> [[String]] -> IO [SingleListBox ()],它根据结果销毁或构建列表框。请注意,返回类型在 IO 中。

查看BarTab示例,我尝试实现以下内容:

  • 列表框的行为bResultControls :: Behavior t [SingleListBox ()],定义为stepper [] eUpdateResultControls.
  • 执行 UI 更新的事件eUpdateResultControls :: Event t [SingleListBox ()]。此事件取决于行为bResultControlsbResults。但是,它还必须更新网络并运行 IO,所以我怀疑Moment并将execute参与其中。这就是我卡住的地方。

我最近的尝试是这样的:

rec
  let
    bResultControls = stepper [] eResultControls
    bResultControlsUpdate = updateResultControls <$> bResultControls <*> bResults

  eResultControls <- execute $ FrameworksMoment . liftIO <$> (bResultControlsUpdate <@ eParam)

但我收到以下类型错误:

Couldn't match type `m0 [SingleListBox ()]'
              with `forall t1. Frameworks t1 => Moment t1 [SingleListBox ()]'
Expected type: IO [SingleListBox ()]
               -> forall t. Frameworks t => Moment t [SingleListBox ()]
  Actual type: IO [SingleListBox ()] -> m0 [SingleListBox ()]
In the second argument of `(.)', namely `liftIO'
In the first argument of `(<$>)', namely
  `FrameworksMoment . liftIO'
In the second argument of `($)', namely
  `FrameworksMoment . liftIO <$> (bResultControlsUpdate <@ eParam)'

我怀疑这将涉及修剪一些行为,或者我可能会以完全错误的方式进行处理。

4

1 回答 1

2

经过更多的阅读和实验,我得到了一些仔细的修剪和重构(如 Heinrich 所暗示的):

networkDescription :: forall t. Frameworks t => Moment t ()
networkDescription = do
  eParam <- choiceSelection cParam

  let bResults = results <$> stepper x eParam

  bResults_ <- trimB bResults

  rec
    let
      bResultControls = stepper [] eResultControls

      mkResultControls :: [SingleListBox ()] -> [[String]] -> FrameworksMoment [SingleListBox ()]
      mkResultControls cs rs = FrameworksMoment $ do
        slResults <- liftIO $ updateResultControls cs rs

        bResults <- now bResults_

        sequence_ [sink sl [items :== (!! i) <$> bResults] | sl <- slResults | i <- [0..]]

        liftIO $ do
          let n = length rs
          set f [clientSize := sz (150 * n) 200]
          set pResults [layout := fill $ boxed "results" $ row n (map (fill . widget) slResults)]
          refit f

        return slResults

    eResultControls <- execute $ (mkResultControls <$> stepper [] eResultControls <*> bResults) <@ eParam

  return ()

(现在有一个小错误,即事件在行为更新之前触发,但这应该很容易修复。)

于 2014-08-06T21:45:41.273 回答