gpt4 book ai didi

haskell - 为什么此 Reflex 代码会导致 Dynamics 以相同的值无限期触发?

转载 作者:行者123 更新时间:2023-12-04 19:03:39 40 4
gpt4 key购买 nike

这个小程序的目的是显示三个按钮,第三个按钮的标签最初是“0”,然后是最后一次点击按钮的索引。现在按钮的数量和其他按钮的标签是恒定的。

当我用 ghcjs 编译这个自包含文件并在浏览器中加载 Main.jsexe/index.html 时,我可以看到两个 traceDyns 在循环中触发,它们的值总是 0。据我所知,什么都不应该发生直到单击按钮,因为 _el_clicked 为系统的其余部分提供支持。

另外,请注意我正在使用 mapDyn (fst . head . Map.toList)为了提取所选按钮的索引 - 我不确定这是否正确,但无论哪种方式,我都不知道是什么导致了无限循环。

{-# LANGUAGE RecursiveDo #-}

module Main where

import Reflex
import Reflex.Dom

import qualified Data.Map as Map

dynButton
:: MonadWidget t m
=> Dynamic t String
-> m (Event t ())
dynButton s = do
(e, _) <- el' "button" $ dynText s
return $ _el_clicked e

-- widget that takes dynamic list of strings
-- and displays a button for each, returning
-- an event of chosen button's index
listChoiceWidget
:: MonadWidget t m
=> Dynamic t [String]
-> m (Event t Int)
listChoiceWidget choices = el "div" $ do
asMap <- mapDyn (Map.fromList . zip [(0::Int)..]) choices
evs <- listWithKey asMap (\_ s -> dynButton s)
k <- mapDyn (fst . head . Map.toList) evs
return $ updated (traceDyn "k" k)

options :: MonadWidget t m => Dynamic t Int -> m (Dynamic t [String])
options foo = do
mapDyn (\x -> ["a", "b", show x]) foo

main :: IO ()
main = mainWidget $ el "div" $ do
rec n <- listChoiceWidget o
o <- options foo
foo <- holdDyn 0 n
display (traceDyn "foo" foo)

最佳答案

看起来您的 listChoiceWidget 代码正在丢弃由 dynButton 构造的点击事件。
listWithKey返回 m (Dynamic t (Map k a)) .在您的情况下, key 类型为 Int并且值为 Event t () (由 dynButton 制作)。

在这一行:

k <- mapDyn (fst . head . Map.toList) evs

您正在转动 Dynamic t (Map Int (Event t ()))Dynamic t Int但是,至关重要的是,当点击事件触发时,您并没有这样做。这条线映射到 evs并生成一个 Dynamic ,该动态将始终包含 Int 到事件的映射中的第一个键,无论事件是否已触发。它将始终是包含 Int 0 的 Dynamic。

您看到循环的原因是:
  • main供稿foo其初始值为 0 到 options
  • 构建了新的选项
  • listChoiceWidget接收新选项并更新列表
  • Ints 到事件的结果映射的第一个键被更新
  • foo接收来自 listChoiceWidget 的 key 更新事件
  • 返回第 2 步,无限期

  • 您需要某种方法来确定最后一个按钮单击事件,而不是从 Map 中检索第一个键。您的 map 已包含显示的每个按钮的点击事件。现在这些事件的类型是 Event t () ,但你真正需要的是 Event t Int ,这样当一个事件触发时,你就可以知道它来自哪个按钮。
    evs' <- mapDyn (Map.mapWithKey (\k e -> fmap (const k) e)) evs
    evs'有类型 Dynamic t (Map Int (Event t Int)) .接下来,我们需要某种方式来组合我们的事件,以便我们有一个使用最近点击的按钮的键触发的事件。
    dynEv <- mapDyn (leftmost . Map.elems . Map.mapWithKey (\k e -> fmap (const k) e)) evs
    dynEv现在有类型 Dynamic t (Event t Int) . Map 的键已经被烘焙到事件中,所以我们不再需要它们了。 Map.elems将我们的事件 map 转换为事件列表,然后 leftmost允许您将一系列事件合并为一个事件。

    来自 docsleftmost :“创建一个新事件,如果列表中的至少一个事件发生,则该事件发生。如果同时发生多个事件,则使用给定函数从左侧折叠它们。”

    最后,我们需要转换您的 Dynamic t (Event t Int)Event t Int .我们将使用 switch ,这需要一个 Behavior t (Event t a)并返回 Event t a .因此,以下行将导致 Event t Int .
    switch (current dynEv)
    current提取 BehaviorDynamic , 和 switch创建“一个将在当前选择的输入事件发生时发生的事件”。

    这是修订版 listChoiceWidget代码。我已经包含了内联类型注释,所以你需要 ScopedTypeVariables启用编译此代码的语言扩展(或者您可以删除注释)。
    listChoiceWidget
    :: forall t m. MonadWidget t m
    => Dynamic t [String]
    -> m (Event t Int)
    listChoiceWidget choices = el "div" $ do
    asMap <- mapDyn (Map.fromList . zip [(0::Int)..]) choices
    evs :: Dynamic t (Map.Map Int (Event t ())) <- listWithKey asMap (\_ s -> dynButton s)
    dynEv :: Dynamic t (Event t Int) <- mapDyn (leftmost . Map.elems . Map.mapWithKey (\k e -> fmap (const k) e)) evs
    return $ switch (current dynEv)

    Here's a gist of the complete file.

    关于haskell - 为什么此 Reflex 代码会导致 Dynamics 以相同的值无限期触发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30885883/

    40 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com