是否可以在Haskell中对有状态节点的异构树进行编码?

是否可以在Haskell中对有状态节点的异构树进行编码?,haskell,types,functional-programming,Haskell,Types,Functional Programming,在Haskell中,建模模块化静态web组件非常容易。视图是一个文档,组件只是一个返回视图的函数: -- Renders a pretty clock clock :: Color -> Html clock color = div ... -- Renders a list of views prettily list :: [Html] -> Html list elements = div ... -- A blue clock blueClock :: Html blu

在Haskell中,建模模块化静态web组件非常容易。视图是一个文档,组件只是一个返回视图的函数:

-- Renders a pretty clock
clock :: Color -> Html
clock color = div ...

-- Renders a list of views prettily 
list :: [Html] -> Html
list elements = div ...

-- A blue clock
blueClock :: Html
blueClock = clock Blue

-- A list with a Blue, a Yellow, and a Red clock
clockList :: Html
clockList = list [
    clock Blue,
    clock Yellow,
    clock Red]
这种方法的问题是当您向事物添加本地状态时。例如:

-- Added "Time" to clock's type
clock :: Color -> Time -> Html
clock color time = div ...

-- A blue clock now has a local state: its time.
blueClock :: Time -> Clock
blueClock = clock Blue

-- A list of clock must be aware of the local state of each child clock.
clockList :: [Time] -> Html
clockList times = list [
    clock Blue   (times !! 0),
    clock Yellow (times !! 1),
    clock Green  (times !! 2)]
type Component state = ... ??? ...

clock :: Color -> Component Time
clock = ...

list :: [Component a] -> Component ()
list = ...

clocks :: Component ()
clocks = list [
    clock Yellow (0, (+ 1)),
    clock Red    (0, (- 1)),
    clock Blue   (0, (+ 2))]

runComponent :: Component a -> IO HtmlNode
父节点必须知道每个子节点的本地状态,这打破了模块化。我们需要一种编码自包含组件的方法,而不是单纯的视图,每个组件将定义如何处理自己的内部状态。例如:

-- Added "Time" to clock's type
clock :: Color -> Time -> Html
clock color time = div ...

-- A blue clock now has a local state: its time.
blueClock :: Time -> Clock
blueClock = clock Blue

-- A list of clock must be aware of the local state of each child clock.
clockList :: [Time] -> Html
clockList times = list [
    clock Blue   (times !! 0),
    clock Yellow (times !! 1),
    clock Green  (times !! 2)]
type Component state = ... ??? ...

clock :: Color -> Component Time
clock = ...

list :: [Component a] -> Component ()
list = ...

clocks :: Component ()
clocks = list [
    clock Yellow (0, (+ 1)),
    clock Red    (0, (- 1)),
    clock Blue   (0, (+ 2))]

runComponent :: Component a -> IO HtmlNode
请注意:

  • 时钟是具有时间类型的本地状态的组件。一个实例需要一个初始状态(这里始终为0)和一个函数,
    state->state
    ,它被称为每个“勾号”来更新其本地状态。有些钟倒着走,有些钟以双倍的速度走

  • 列表
    是没有本地状态的组件。它只是创建了一些包含许多组件的漂亮HTML列表。它根本不知道内部时钟的局部状态

  • runComponent
    负责赋予最终应用程序生命,包括正确调用每个子组件的状态


  • 我尝试了无数种用类型形式化这种直觉的方法,但我找不到任何令人满意的方法。问题包括组件可以具有不同类型的状态,以及“回调”(例如,纯按钮)必须影响包含它的组件的状态。如何在Haskell的类型系统中对此类系统进行编码?

    尝试存在类型。您描述的问题听起来与Snaplet在snap server框架中解决的问题非常相似;它基本上使用镜头以自己的状态运行Snaplet。你可以考虑阅读SNAPLET是如何工作的,看看它们的方法是否适合你。我正在寻找这样的建议,谢谢指针!我不清楚你在问什么。如果列表中的数据取决于当前时间,那么列表的值当然也取决于时间。在纯函数设置中,无法“隐藏”这种依赖关系。您可以通过将某个对象的内部状态设置为函数的参数,并将该状态向下传递,来“隐藏”该对象的内部状态。例如,
    listOfWords=(“lih”、\x->div[(“foo”、\x->div(strx))、(“bar”、\x->div(str(x+x))、(“biz”、\x->div(str(x*3))))
    。这里,每个组件都有一个id(“foo”、“bar”…)和一个内部状态
    x
    listOfWords
    不知道其子项的状态。函数
    runComponent
    将传递状态环境,以便每个节点根据其id接收自己的状态。这将隐藏在允许模块化的意义上,@BenjaminHodgson。