gpt4 book ai didi

haskell - 复合模式是否可以用于从树生成 HTML 并处理缩进,或者这本质上是不可能的?

转载 作者:行者123 更新时间:2023-12-04 18:11:17 26 4
gpt4 key购买 nike

我看了this video关于复合模式,主要示例是如何使用该模式作为一种手段,从描述待办事项列表的树结构中生成 HTML 代码,其中每个项目又可以是待办事项列表,这似乎是一个方便的测试平台,所以这里是一个目标 HTML:

[ ] Main
<ul>
<li>[ ] 1.</li>
<li>[ ] 2.
<ul>
<li>[ ] 2.1</li>
<li>[ ] 2.2</li>
</ul>
</li>
<li>[ ] 3.</li>
</ul>
(对不起,如果顶部 [ ] Main 没有意义,但我不知道 HTML;此外,我相信这与我的问题无关。)
我知道设计模式主要是一种面向对象的“东西”,但是我经常引用文章 Design Patterns in Haskell了解如何在函数式编程中重新解释它们,目的是更深入地理解它们。
至于复合模式,那篇文章基本上是这样写的:

Composite. Recursive algebraic data types. Especially prominent since there's no built-in inheritance.


因此,我认为在 Haskell 中尝试它会很容易,我想出了以下代码:
import Data.List (intercalate)

data Todo = Todo String | TodoList String [Todo] deriving Show

showList' :: Todo -> String
showList' (Todo s) = "[ ] " ++ s
showList' (TodoList s ts) = "[ ] " ++ s
++ "<ul><li>"
++ intercalate "</li><li>" (map showList' ts)
++ "</li></ul>"
像这样喂
putStrLn $ showList' $ TodoList "Main" [Todo "1.", TodoList "2." [Todo "2.1", Todo "2.2"], Todo "3."]
生成此输出
[ ] Main<ul><li>[ ] 1.</li><li>[ ] 2.<ul><li>[ ] 2.1</li><li>[ ] 2.2</li></ul></li><li>[ ] 3.</li></ul>
这基本上是我的问题顶部的 HTML 呈现在一行上:从我的 showList' 实现中可以清楚地看到一旦调用它(在recusion的任何深度)返回一个字符串,该字符串不会以任何方式改变,只是与其他字符串连接。所以我觉得我无能为力 showList'添加 \n和空格以达到格式良好的 HTML。
我尝试了一下,添加了空格和 \n ,但尤其是在阅读 Composite as a monoid 时由 Mark Seemann我开始对我正在尝试做的事情的可行性有点怀疑......
我很想得出 的结论。如果composite 是一个幺半群,这意味着各种项目以相同的方式两个两个组合在一起,而不管它们在树中的深度如何 ,因此这意味着不可能为良好的格式添加空间,因为要添加的空间量取决于被连接的两个元素周围的上下文,而不仅仅是两个元素。
但是,我不确定我的推理,因此我在这里问。

最佳答案

这个回答有点绕。 (评论已经包含一个完全有效且更直接的建议。)
我们可以定义这个辅助类型:

data Todo' a = Todo' String 
| TodoList' String [a]
deriving Show
就像 Todo ,但在“递归”步骤中,而不是另一个 Todo ,我们有一个多态值。我们可以放任何我们想要的东西,包括原来的 Todo :
peel :: Todo -> Todo' Todo
peel todo = case todo of
Todo s -> Todo' s
TodoList s xs -> TodoList' s xs
我们到底为什么要这样做?好吧,有时我们想讨论递归数据类型的单个“层”,留下下面的层可能包含什么的问题。
现在我们要重构 showList'用另一种方式。一、这个辅助功能 cata :
cata :: (Todo' a -> a) -> Todo -> a
cata f todo = case peel todo of
Todo' s -> f (Todo' s)
TodoList' s xs -> f (TodoList' s (map (cata f) xs))
这个函数说,如果我们有办法转换单个 Todo'层携带来自较低层的某种结果到当前层的结果,然后我们能够转换整个 Todo值转化为结果。 showList'现在可以写成
showList'' :: Todo -> String
showList'' todo = cata layer todo
where
layer :: Todo' String -> String
layer (Todo' s) = "[ ] " ++ s
layer (TodoList' s xs) = "[ ] " ++ s
++ "<ul><li>"
++ intercalate "</li><li>" xs
++ "</li></ul>"
请注意,此版本没有显式递归, cata照顾它。
好的。现在,正如您所提到的,缩进的问题在于一层的结果取决于上面的层数。在 Haskell 中表达这种依赖关系最自然的方式是使用 Int -> String 类型的函数。 ,其中 Int是上面的层数。
当我们写 showList' ,我做了 cata返回 String .如果我们让它返回一个函数 Int -> String 会怎样?反而?
showIndented :: Todo -> String
showIndented todo = cata layer todo 0
where
layer :: Todo' (Int -> String) -> Int -> String
layer todo' indentation =
let tabs = replicate indentation '\t'
in case todo' of
Todo' s ->
tabs ++ "<li>[ ] " ++ s ++ "</li>\n"
TodoList' s fs ->
tabs ++ "[ ] " ++ s ++ "\n" ++
tabs ++ "<ul>\n" ++
foldMap ($ succ indentation) fs ++
tabs ++ "</ul>\n"
foldMap ($ succ indentation) xs bit 正在获取一个函数列表,使用当前缩进级别 + 1 调用所有函数,并将结果字符串连接起来。

关于haskell - 复合模式是否可以用于从树生成 HTML 并处理缩进,或者这本质上是不可能的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67037663/

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