我是函数式编程的新手,我决定在Purescript中构建一个应用程序。我遇到了第一个障碍,我不确定如何从概念上思考这个问题。
我不是在寻找代码,而是在功能上思考这个问题。
我有一份数据清单。具体来说,像是
[ {a :: String, b :: String, c :: String} ]
我想使用提供的记录(以及上述类型的列表)创建Html
(purescript-halogen
类型)的列表。
所以,我会有一个功能
buildElements :: forall p i. MyRecordObject -> Array (HTML p i)
现在,我想我需要给这个函数结果类型一个Monad计算上下文(purescript Eff
就像Haskell IO
)
类似于:
buildElements :: forall p i. MyRecordObject -> Eff (Array (HTML p i))
我的第一个想法是模糊地创建一个类似
的列表take $ length xs $ repeat ARecordObject
然后将记录映射到该列表,但我不确定如何将其转换为代码。这似乎不对,因为我的计划涉及改变ARecordObject
的状态,这是一个禁忌。
然后我发现了这个功能:
forEach :: forall e a. Array a -> (a -> Eff e Unit) -> Eff Unit
看起来几乎完美!我得到一个数组,我给它一个函数,以某种方式将记录中的属性分配给这个新数组......但不,等等......我正在考虑非功能性。
我在这里真的有些不知所措。基本上,我想创建类似<li></li>
元素列表的内容,我在其中为每个项目分配属性。
E.g
我提供了一条记录:
[ { id: "id1", name: "name1", class: "class1", content: "content1" }
, { id: "id2", name: "name2", class: "class2", content: "content2" } ]
我希望函数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 ] ]
其中rec
是recordObject的名称(显然这两个数组不相同,但实际映射到初始记录上)。
(点语法是类似于标准getter / setter表示法的purescript记录语法表示法)
答案 0 :(得分:15)
我的第一个想法是模糊地创建一个类似
的列表take $ length xs $ repeat ARecordObject
然后将记录映射到该列表,但我不确定如何 将其转换为代码。从我的计划来看,无论如何它似乎都是错的 涉及改变
ARecordObject
的状态,这是一个禁忌。
功能程序员不要只是避免变异,因为它不是 - 否则(实际上,很多功能程序都会谨慎使用受控制的可变性) - 我们这样做是因为它产生更安全,更简单的代码。
即便如此:你正在思考我所说的&#34; alloc-init模式&#34;,其中你创造了某种&#34;空&#34;价值,然后去计算它的属性。原谅我的健康,但这是一个从根本上被打破的编程模型,从手动内存管理的时代遗留下来;使用它的代码永远不会安全,依赖它的抽象将永远是漏洞。这个成语并不适合任何比C更高级的语言,但是,如果我每次看到这样的代码都有一英镑......
var foo = new Foo();
foo.Bar = new Bar();
foo.Bar.Baz = new Baz();
......我会成为一个富翁(na na na)。默认应该是在您知道它们将会是什么样之后创建对象:
var foo = new Foo(new Bar(new Baz()));
这更简单 - 你只是计算一个值,而不是进入指针引用的内存来更新其内容 - 更重要的是它更安全,因为它更安全type-checker确保您不会忘记某个属性,并且它允许您使Foo
不可变。最干净的命令性代码是功能代码 - 只有在必要的性能(或语言强迫你的手)时,你才应该是必须的。
无论如何,咆哮。关键在于,你必须通过强制性思考来使自己的生活更加艰难。只需编写一个从单个对象计算单个<li>
的函数......
toLi :: MyRecord -> HTML
toLi x = li [ id_ x.id, name_ x.name, class_ x.class ] [ text x.content ]
...(请注意,我不是以某种方式创建&#34;空&#34; li
然后填充其值),然后在输入列表中map
toLis :: [MyRecord] -> [HTML]
toLis = map toLi
这也是我在JS中的表现,即使我不是要求使用该语言。没有副作用,没有变异,不需要Eff
- 只是简单,安全,纯粹的功能代码。