从功能上思考.在Haskell/Purescript中构建一个新数组

clo*_*jur 5 haskell functional-programming purescript

我是函数式编程的新手,我决定在Purescript中构建一个应用程序.我遇到了第一个障碍,我不确定如何从概念上思考这个问题.

我不是在寻找代码,而是在功能上思考这个问题.

我有一个数据列表.具体来说,就像

[ {a :: String, b :: String, c :: String} ]
Run Code Online (Sandbox Code Playgroud)

我想通过使用提供的记录(以及上面类型的列表)创建Html(这是一种purescript-halogen类型)的列表.

所以,我会有一个功能

buildElements :: forall p i. MyRecordObject -> Array (HTML p i)
Run Code Online (Sandbox Code Playgroud)

现在,我想我需要给这个函数结果类型一个Monad计算上下文(purescript Eff就像Haskell IO)

所以类似于:

buildElements :: forall p i. MyRecordObject -> Eff (Array (HTML p i))
Run Code Online (Sandbox Code Playgroud)

我的第一个想法是模糊地创建一个类似的列表

take $ length xs $ repeat ARecordObject
Run Code Online (Sandbox Code Playgroud)

然后将记录映射到该列表,但我不确定如何将其转换为代码.无论如何,这似乎是错误的,因为我的计划涉及改变状态ARecordObject,这是一个禁忌.

那么我发现了这个功能:

forEach :: forall e a. Array a -> (a -> Eff e Unit) -> Eff Unit
Run Code Online (Sandbox Code Playgroud)

看起来几乎完美!我得到一个数组,我给它一个函数,以某种方式将记录中的属性分配给这个新数组......但不,等等......我正在考虑非功能性.

我真的在这里有点亏.基本上,我想创建类似于<li></li>元素列表的东西,我在其中为每个项目分配属性.

例如

我提供了一条记录:

[ { id: "id1", name: "name1", class: "class1", content: "content1" }
, { id: "id2", name: "name2", class: "class2", content: "content2" } ]
Run Code Online (Sandbox Code Playgroud)

我想要一个foo返回数组的函数:

[ li [ id_ rec.id, name_ rec.name, class_ rec.class ] [ text rec.content ]
, li [ id_ rec.id, name_ rec.name, class_ rec.lass ] [ text rec.content ] ]
Run Code Online (Sandbox Code Playgroud)

其中rec是recordObject的名称(显然这两个数组不相同,但实际上映射在初始记录上).

(点语法是类似于标准getter/setter表示法的purescript记录语法表示法)

Ben*_*son 15

我的第一个想法是模糊地创建一个类似的列表

take $ length xs $ repeat ARecordObject
Run Code Online (Sandbox Code Playgroud)

然后将记录映射到该列表,但我不确定如何将其转换为代码.无论如何,这似乎是错误的,因为我的计划涉及改变状态ARecordObject,这是一个禁忌.

功能程序员不仅避免变异,因为它是禁忌(实际上,许多功能程序都会谨慎使用受控剂量的可变性) - 我们这样做是因为它产生更安全,更简单的代码.

也就是说:你正在考虑我称之为"alloc-init模式",其中你创建了某种"空"值,然后继续计算它的属性.原谅我的愤怒,但这是一个从根本上破坏的编程模型,从手动内存管理的时代遗留下来; 使用它的代码永远不会安全,依赖它的抽象将永远是漏洞.这个成语不适合任何比C更高级的语言,然而,如果我每次看到这样的代码时都有一英镑......

var foo = new Foo();
foo.Bar = new Bar();
foo.Bar.Baz = new Baz();
Run Code Online (Sandbox Code Playgroud)

......我会成为一个有钱人(娜娜娜).默认应该是在您知道它们的外观后创建对象:

var foo = new Foo(new Bar(new Baz()));
Run Code Online (Sandbox Code Playgroud)

这更简单 - 你只是计算一个值,而不是到达指针所引用的内存以更新其内容 - 更重要的是它更安全,因为类型检查器确保你没有忘记属性它允许你使Foo不可变的.最干净的命令性代码是功能代码 - 只有在必要的性能(或语言强迫你的手)时,你才应该这样做.


无论如何,咆哮过来.重点在于,通过强制性思考,你使自己的生活变得更加艰难.只需编写一个<li>从单个对象计算单个函数的函数......

toLi :: MyRecord -> HTML
toLi x = li [ id_ x.id, name_ x.name, class_ x.class ] [ text x.content ]
Run Code Online (Sandbox Code Playgroud)

...(请注意,我不是以某种方式创建一个"空" li然后填充其值),然后map它在您的输入列表上.

toLis :: [MyRecord] -> [HTML]
toLis = map toLi
Run Code Online (Sandbox Code Playgroud)

这就是我在JS中的表现,即使我不需要语言.没有副作用,没有突变,不需要Eff- 只是简单,安全,纯粹的功能代码.