gpt4 book ai didi

haskell - 幺半群的实际用途是什么?

转载 作者:行者123 更新时间:2023-12-03 11:33:24 28 4
gpt4 key购买 nike

我正在阅读 Learn You a Haskell 并且我已经介绍了应用程序,现在我在使用 monoids。我对两者的理解都没有问题,尽管我发现 applicative 在实践中很有用,而 monoid 并非如此。所以我想我不了解 Haskell 的一些东西。

先说Applicative ,它创建了类似统一语法的东西来对“容器”执行各种操作。所以我们可以使用普通函数对 Maybe 执行操作, 列表, IO (我应该说单子(monad)吗?我还不知道单子(monad)),功能:

λ> :m + Control.Applicative
λ> (+) <$> (Just 10) <*> (Just 13)
Just 23
λ> (+) <$> [1..5] <*> [1..5]
[2,3,4,5,6,3,4,5,6,7,4,5,6,7,8,5,6,7,8,9,6,7,8,9,10]
λ> (++) <$> getLine <*> getLine
one line
and another one
"one line and another one"
λ> (+) <$> (* 7) <*> (+ 7) $ 10
87

所以 applicative 是一种抽象。我认为我们可以没有它,但它有助于清楚地表达一些想法模式,这很好。

现在,让我们来看看 Monoid .它也是抽象且非常简单的一种。但它对我们有帮助吗?对于书中的每个示例,似乎都有更清晰的方法来做事:
λ> :m + Data.Monoid
λ> mempty :: [a]
[]
λ> [1..3] `mappend` [4..6]
[1,2,3,4,5,6]
λ> [1..3] ++ [4..6]
[1,2,3,4,5,6]
λ> mconcat [[1,2],[3,6],[9]]
[1,2,3,6,9]
λ> concat [[1,2],[3,6],[9]]
[1,2,3,6,9]
λ> getProduct $ Product 3 `mappend` Product 9
27
λ> 3 * 9
27
λ> getProduct $ Product 3 `mappend` Product 4 `mappend` Product 2
24
λ> product [3,4,2]
24
λ> getSum . mconcat . map Sum $ [1,2,3]
6
λ> sum [1..3]
6
λ> getAny . mconcat . map Any $ [False, False, False, True]
True
λ> or [False, False, False, True]
True
λ> getAll . mconcat . map All $ [True, True, True]
True
λ> and [True, True, True]
True

所以我们注意到了一些模式并创建了新的类型类......好吧,我喜欢数学。但是从实际的角度来看, Monoid 的意义何在? ?它如何帮助我们更好地表达想法?

最佳答案

加布里埃尔冈萨雷斯在他的博客中写了很多关于为什么你应该关心的信息,你真的应该关心。您可以阅读 here (另见 this )。

它是关于 API 的可扩展性、架构和设计的。这个想法是“传统架构”说:

Combine a several components together of type A to generate a "network" or "topology" of type B



这种设计的问题在于,随着您的程序扩展,重构时您的 hell 也会如此。

所以你想改变模块 A 来改进你的设计或领域,所以你这样做了。哦,但是现在依赖于 A 的模块 B 和 C 坏了。你修复了B,太好了。现在你修复了 C。现在 B 又坏了,因为 B 也使用了 C 的一些功能。我可以永远继续下去,如果你曾经使用过 OOP - 你也可以。

然后就是 Gabriel 所说的“Haskell 架构”:

Combine several components together of type A to generate a new component of the same type A, indistinguishable in character from its substituent parts



这也优雅地解决了这个问题。基本上:不要对模块进行分层或扩展以制作专门的模块。
相反,结合。

所以现在,鼓励的是,不要说“我有多个 X,所以让我们创建一个类型来表示它们的联合”,而是说“我有多个 X,所以让我们将它们组合成一个 X”。或者用简单的英语:“让我们首先制作可组合类型。” (你感觉到幺半群的潜伏了吗?)。

想象一下,您想为您的网页或应用程序制作一个表单,并且您拥有创建的模块“个人信息表单”,因为您需要个人信息。后来你发现你也需要“更改图片格式”所以就这么快写了。现在你说我想把它们结合起来,所以我们来做一个“个人信息和图片表格”模块。在现实生活中的可扩展应用程序中,这可能而且确实会失控。可能不是表格,而是演示,您需要撰写和撰写,因此您最终会得到“个人信息 & 更改图片 & 更改密码 & 更改状态 & 管理 friend & 管理愿望 list & 更改 View 设置 & 请不要再扩展我&请&请停止!&停止!!!!“模块。这并不漂亮,您将不得不在 API 中管理这种复杂性。哦,如果你想改变任何东西 - 它可能有依赖关系。所以..是的..欢迎来到 hell 。

现在让我们看看另一个选项,但首先让我们看看它的好处,因为它会引导我们找到它:

These abstractions scale limitlessly because they always preserve combinability, therefore we never need to layer further abstractions on top. This is one reason why you should learn Haskell: you learn how to build flat architectures.



听起来不错,所以,与其制作“个人信息表单”/“更改图片表单”模块,不如停下来想想我们是否可以让这里的任何东西可组合。好吧,我们可以做一个“表格”,对吧?也会更抽象。
然后为您想要的所有内容构建一个,将它们组合在一起并获得一种形式就像任何其他形式一样是有意义的。

因此,您不会再得到一棵凌乱的复杂树,因为您采用两种形式并获得一种形式的关键。所以 Form -> Form -> Form .正如您已经清楚地看到的那样,这个签名是 mappend 的一个实例。 .

替代方案和传统架构可能看起来像 a -> b -> c然后 c -> d -> e接着...

现在,有了表格,它就没有那么具有挑战性了。挑战在于在现实世界的应用程序中使用它。要做到这一点,只需尽可能多地问自己(因为它得到了返回,正如你所看到的):我怎样才能使这个概念可组合?既然幺半群是实现这一目标的一种简单方法(我们想要简单),首先问问自己:这个概念怎么是一个幺半群?

旁注:幸运的是,Haskell 非常不鼓励您扩展类型,因为它是一种函数式语言(没有继承)。但是仍然可以为某事创建一个类型,为某事创建另一种类型,并在第三种类型中将两种类型都作为字段。如果这是为了作曲 - 看看你是否可以避免它。

关于haskell - 幺半群的实际用途是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26230530/

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