简体   繁体   English

如何在随机值计算的haskell程序中构造monad?

[英]how to structure monads in haskell programs which compute on random values?

I have a program that's almost pure mathematical computation. 我有一个几乎纯数学计算的程序。 The problem is that some of those computations operate on monte carlo generated values. 问题是这些计算中的一些对monte carlo生成的值进行操作。

It seems like I have two design options: 看起来我有两个设计选择:

Either all my computation functions take additional parameter which contains a pre-generated monte carlo chain. 我的所有计算函数都采用包含预生成的蒙特卡罗链的附加参数。 This lets me keep pure functions everywhere, but since there's functions that call other functions this adds a lot of line noise to the code base. 这让我可以在任何地方保留纯函数,但由于有调用其他函数的函数,这会给代码库增加很多行噪声。

The other option is to make all the computation functions monadic. 另一种选择是使所有计算函数都是monadic。 This seems unfortunate since some of the functions aren't even using those random values they're just calling a function which calls a function which needs the random values. 这似乎很不幸,因为有些函数甚至没有使用那些随机值,它们只是调用一个调用需要随机值的函数的函数。

Is there any guidance regarding the preferred design here? 这里有关于首选设计的指导吗? Specifically, the separation of monadic / non-monadic functions in the code where monte carlo values are concerned? 具体而言,在涉及蒙特卡罗值的代码中分离monadic / non-monadic函数?

The other option is to make all the computation functions monadic. 另一种选择是使所有计算函数都是monadic。 This seems unfortunate since some of the functions aren't even using those random values they're just calling a function which calls a function which needs the random values. 这似乎很不幸,因为有些函数甚至没有使用那些随机值,它们只是调用一个调用需要随机值的函数的函数。

I would suggest following this approach, and I disagree with your assessment that it's "unfortunate." 我建议采用这种方法,我不同意你的评估,认为这是“不幸的”。 What monads are good at precisely is separating your pure code from your side effecting code. 什么单子都擅长正是从你身边影响的代码分离的纯代码。 Your pure functions can just have pure types, and the Functor / Applicative / Monad methods serve to "hook them up" with the random generation parts. 你的纯函数可以只有纯类型,而Functor / Applicative / Monad方法可以用随机生成部分“连接起来”。 Meditate on the signatures of the standard operations (here specialized to some idealized Random monad type): 冥想标准操作的签名(这里专门针对某些理想化的Random monad类型):

-- Apply a pure function to a randomly selected value.
fmap :: (a -> b) -> Random a -> Random b

-- Apply a randomly selected function to a randomly selected argument.
-- The two random choices are independent.
(<*>) :: Random (a -> b) -> Random a -> Random b

-- Apply a two-argument function to a randomly selected arguments.
-- The two random choices are independent.
liftA2 :: (a -> b -> c) -> Random a -> Random b -> Random c

-- Make a `Random b` choice whose distribution depends on the value
-- sampled from the `Random a`.
(>>=) :: Random a -> (a -> Random b) -> Random b

So the reformulated version of your approach is: 所以你的方法的重新制定版本是:

  • Write pure functions wherever you can. 尽可能编写纯函数。
  • Adapt these pure functions to work on the random values by using the Functor / Applicative / Monad class operations. 通过使用Functor / Applicative / Monad类操作,调整这些纯函数以处理随机值。
  • Wherever you spot a function that's mentioning the Random type superfluously, figure out how to factor the Random part out using those classes' operations (or the copious utility functions that exist for them). 无论你何时发现一个多余地提及Random类型的函数,弄清楚如何使用这些类的操作(或为它们存在的丰富的实用函数)将Random部分考虑在内。

This is not specific to random number generation, by the way, but applies to any monad. 顺便说一下,这不是特定于随机数生成,而是适用于任何 monad。

You might enjoy reading this article, and might want to check out the author's random generation monad library: 您可能喜欢阅读本文,并可能想查看作者的随机生成monad库:

I doubt you need to follow the article's approach of using free monads for modeling, but the conceptual bits about probability distribution monads will likely be of some help. 我怀疑你需要遵循文章使用免费monad进行建模的方法,但关于概率分布monad的概念性位可能会有所帮助。

tl;dr: Consider to abstract the random function generator and pass it as an argument. tl; dr:考虑抽象随机函数生成器并将其作为参数传递。 Haskells type classes should help you to hide that abstraction as much as possible. Haskells类型类应该帮助您尽可能地隐藏该抽象。

Unfortunately, there is no silver bullet here. 不幸的是,这里没有银弹。 Since you are using side effects, your "functions" simply aren't functions in the proper sense. 由于您正在使用副作用,因此您的“功能”根本不是正确意义上的功能。 Haskell does not allow you to hide that fact (which makes up the largest part of its safety guarantees). Haskell不允许你隐藏这个事实(这是其安全保证的最大部分)。 So in some way you will need to express this fact. 所以在某种程度上你需要表达这个事实。 You also seem to confuse the difference between monadic operations and (plain) functions: A function that (indirectly) uses random values is implicitly monadic. 你似乎也混淆了monadic操作和(普通)函数之间的区别:(间接)使用随机值的函数是隐式monadic。 A non-monadic function can always be used inside a monadic operation. 非monadic函数总是可以在monadic操作中使用。 So you should probably implement all truly non-monadic functions as such and see how far that carries. 所以你应该实现所有真正的非monadic函数,看看它有多远。

As a completely unrelated side-note: If lazyness is not a requirement and Haskells strong safety is too much a burden for you, but you still want to write (mostly) functional code, you could give OCaml a try (or any other ML dialect for that matter). 作为一个完全不相关的旁注:如果懒惰不是一个要求而且Haskells强大的安全性对你来说太过沉重,但你仍然想写(大部分)功能代码,你可以试试OCaml(或任何其他ML方言)对于这个问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM