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

时间:2017-01-14 07:25:58

标签: haskell functional-programming purescript

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

  

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

我有一份数据清单。具体来说,像是

[ {a :: String, b :: String, c :: String} ]

我想使用提供的记录(以及上述类型的列表)创建Htmlpurescript-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记录语法表示法)

1 个答案:

答案 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 - 只是简单,安全,纯粹的功能代码。