我有一个编程问题,我知道如何在Ruby中解决这个问题,但我不知道Clojure中最好的方法(并且认为可能有一种优雅的方法-考虑到功能思维)。
这个问题可以简化如下:
我有一个3升的桶,装满了水。水桶底部有一个洞,漏水10毫升/秒(即需要300秒/5分钟才能清空)。我有一杯100 mL容量的水,我可以用它把新的水倒进桶里。
我只能把玻璃杯全部倒进水桶里,不能部分倒入。倒水是瞬间发生的。
规划出一套时间步骤,让我可以倒杯水到桶里。
我知道用代数做这件事有一个很明显的方法,但实际的问题是“漏出率”随时间的变化,而“新玻璃体积”并不总是等于100 mL,因此不容易用封闭的形式来解决。
解决这一问题的Ruby方法是使用“桶实例”跟踪桶卷,并在多个时间步骤进行测试,以确定存储桶是否有100个mL空间。如果是这样的话,倒掉玻璃杯,并添加到“水桶实例”中的水。继续时间步骤,观察桶量。
我希望我所描述的是清楚的。
发布于 2014-10-23 02:32:27
函数编程最重要的概念之一是,任何没有外部副作用的变异都可以被卸载到不可变的函数参数绑定中。
这里,模拟的时间和桶的级别是主要的函数参数,并对每个递归调用进行更新。将其它参数建模为时间函数。我们可以想象这些函数中的每一个实际上都是基于时间增量的懒序列,就像fill-times函数本身一样。或者用向量中的查找来建模的分段线性方程组,或者是什么。
user>
(defn fill-times
[time level
{:keys [sample-rate calc-bucket-size calc-leak-rate calc-glass-size]
:as params}]
(loop [t time l level]
(let [input-capacity (calc-glass-size time)
bucket-capacity (calc-bucket-size time)
has-room (> (- bucket-capacity l) input-capacity)
leak-delta (* (calc-leak-rate) sample-rate -1)]
(if has-room
(lazy-seq (cons t (fill-times t (+ l input-capacity)
params)))
(recur (+ t sample-rate) (+ l leak-delta))))))
#'user/fill-times
user> (take 50 (fill-times 0 0 {:sample-rate 1
:calc-bucket-size (constantly 3000)
:calc-leak-rate (constantly 10)
:calc-glass-size (constantly 100)}))
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 11 21 31 41 51 61 71 81 91 101 111 121 131 141 151 161 171 181 191 201)当有足够的空间,玻璃被倾倒(当然是立即填满),我们做了一个时间记录,再次调用函数,以获得以下时间。当没有空间时,我们重复,更新时间和桶的水平。其结果是一个(假设无限的)懒惰的时间序列,玻璃可以被倒空(假设玻璃杯立即装满,并立即倾倒)。
发布于 2014-10-23 02:08:14
我对Clojure没有太多的经验,但有一种方式是在时间步骤中懒洋洋地收集状态值。惰性地从以前的状态值计算每个状态值。
这是一个递推方程,也称为差分方程。它计算新值作为以前值的函数,而不覆盖它们。
状态值可以仅仅是桶级,也可以是保存(time、bucket_level、pour_in_count)的元组。
https://stackoverflow.com/questions/26519916
复制相似问题