The best way to express this sort of iterative procedure in Haskell is as an infinite list of each successive result. Piecing together your four steps yields a notion of a function from a solution to a different (better) solution; all you need to do is apply this infinitely many times. The user of your function can then use any list function to get the answer: solve s0 !! numIterations
, or find stoppingCondition $ solve s0
, or whatever you want.
为了到这里来,请说明每项职能类型。
moves :: Solution -> [Move]
Given a possible solution, figure out the possible changes you can make.
value :: Solution -> Move -> Double
Given a solution and a move, evaluate it and record that value as some real number.
choose :: Solution -> [Move] -> Move
Given a solution and a list of moves, pick the best one.
apply :: Solution -> Move -> Solution
Given a move, apply it to an existing solution to get a new one.
您想写一份像<代码>等类型的职务。 解决办法-> (Solution -> Bool)-> Solutions,其中采用初步解决办法,并为执行你的算法规定一个停止条件。
相反,请将此列入一个明确清单;这意味着你只是删除了上线,并填写了<代码>。 解决方案-> [Solution]。
import Data.Ord
import Data.List
-- moves, value, and apply are domain-specific
choose :: Solution -> [Move] -> Move
choose s ms = maximumBy (comparing $ value s) ms
solve :: Solution -> [Solution]
solve = iterate $ s -> apply s . choose s $ moves s
此处的关键是<代码>iterate * (a->a)-> a-> [a],其中反复将功能应用到价值上,并给你结果——实际上是对你的算法的描述。
然而,我真的写这句话的方式是:
import Data.Ord
import Data.List
solve :: Ord o => (s -> [m]) -> (s -> m -> o) -> (s -> m -> s) -> s -> [s]
solve moves value apply = iterate step
where step s = apply s . choose s $ moves s
choose s = maximumBy (comparing $ value s)
这样做的好处是,你可以重新利用这个相同的通用结构来any 问题领域。 你们需要做的是提供<条码>第<0>>>>、<条码>、<> 数值/代码>和<条码>应用代码>功能! 视我的情绪,我可以改写如下:
import Control.Applicative
import Data.Ord
import Data.List
solve :: Ord o => (s -> [m]) -> (s -> m -> o) -> (s -> m -> s) -> s -> [s]
solve moves value apply = iterate step
where step = (.) <$> apply <*> choose <*> moves
choose = maximumBy . comparing . value
在此,我们使用参考性通知说,我们实际上只是在<条码>(......)中选择移动条码>(即<条码>适用,选择移动<条/条码>),条件是这些功能中的每一功能都隐含地通过一个参数<条码>(<>条/条码>)(读者参考)。 如果我们真的想把事情打上钩,我们就可以写一下。
import Control.Applicative
import Data.Ord
import Data.List
solve :: Ord o => (s -> [m]) -> (s -> m -> o) -> (s -> m -> s) -> s -> [s]
solve moves value apply =
iterate $ (.) <$> apply <*> maximumBy . comparing . value <*> moves
任何这些信条都将完全满足你们的需要。 (但:在你的任何职能中,没有任何影响/mon,因此是随机性的。) 不过,你使这一术语容易。
但是,就cks而言,请考虑State
monad。 这代表了某种环境的计算,因此,<代码> State s a iso吗?code>s -> (a,s) - something which can see the state and potential update it. 这里,您的职能签名左边的所有<代码>Solution ->s都将消失,-> Solutions
s on the right。 这将使你与你一道工作。
moves :: State Solution [Move]
value :: Move -> State Solution Double
choose :: [Move] -> State Solution Move
apply :: Move -> State Solution ()
这意味着,你会采取一些行动:<条码>步骤条码>:
import Control.Applicative
import Control.Monad.State
import Data.Ord
import Data.List
choose :: [Move] -> State Solution Move
choose = let val m = do v <- value m
return (m,v)
in fst . maximumBy (comparing snd) <$> mapM val ms
step :: State Solution ()
step = apply =<< choose =<< moves
You could make this more point-free, or make it polymorphic just as above, but I won t do that here. The point is that once you have step
, you can generate answers with runState . last $ replicateM_ numIterations step
, or given a whileM
function, runState $ whileM (stoppingCondition :: State Solution Bool) step
. Again, the user can decide how to stop it. Your moves
and value
functions would probably query the state with get :: State s s
; apply
would probably use modify :: (s -> s) -> State s ()
to tweak the state without needing to pull it back out. You can see the similarity with the structure from above in these types; and in fact, you can see that structure in the definition of step
, as well. Each one says "string together apply
, choose
/value
, and moves
", which is the definition of your algorithm.
这两者的带回家的讯息是,你想要避免明显的 lo/入侵,正如你正确意识到的那样。 如果你认为有必要考虑这一算法,那么State
monad似乎是一种自然结构,因为它掩盖了你所想的这些必要特征。 然而,它已经缩小了:例如,一切已经变成了 mo,而且——最重要的是——除<条码>外的其他功能——能够改变所节省的解决办法。 如果您认为这一算法是每当得出new<>>>,那么你就会获得的概念。 解决办法-> Solutions
,从中可使用iterate
,以获得一份完整的清单。