English 中文(简体)
使用Haskell monads
原标题:When to use Haskell monads

• 在Haskell实施综合优化算法:

Given an initial candidate solution, repeat until stopping criteria are met:

  1. Determine possible moves
  2. Evaluate possible moves
  3. Choose a move
  4. Make move, record new candidate solution, update search state

我可以写出第1-4级步骤的职能,并将它们合并到休养职能中,以便处理 lo和从一种迭代到另一种状态,但我有一种含糊的想法,即mon素适用。

在Haskell表达这种程序的最佳方式是什么?

最佳回答

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.

为了到这里来,请说明每项职能类型。

  1. moves :: Solution -> [Move]
    Given a possible solution, figure out the possible changes you can make.
  2. value :: Solution -> Move -> Double
    Given a solution and a move, evaluate it and record that value as some real number.
  3. choose :: Solution -> [Move] -> Move
    Given a solution and a list of moves, pick the best one.
  4. 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都将消失,-> Solutionss on the right。 这将使你与你一道工作。

  1. moves :: State Solution [Move]
  2. value :: Move -> State Solution Double
  3. choose :: [Move] -> State Solution Move
  4. 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,以获得一份完整的清单。

问题回答

http://hackage.haskell.org/ Packages/archive/mtl/2.0.1.0/doc/html/Control-Monad-State-Lazy.html>。

import Control.Monad.State

type SearchState = ...
type Move = ...
type Fitness = ...

determineMoves :: State SearchState [Move]
determineMoves = do
  -- since determineMoves is in the State monad, we can grab the state here
  st <- get
  ...

evaluateMoves :: [Move] -> [(Move, Fitness)]
evaluateMoves = ...

chooseMove :: [(Move, Fitness)] -> Move
chooseMove = ...

-- makeMove is not itself monadic, but operates on the SearchState
-- type we re threading through with the State monad
makeMove :: Move -> SearchState -> SearchState
makeMove m st = ...

loop :: State SearchState ()
loop = do
  moves <- determineMoves
  let candidates = evaluateMoves moves
      move = chooseMove candidates
  -- we pass a function (SearchState -> SearchState) to modify in 
  -- order to update the threaded SearchState
  modify (makeMove move)
  loop

通知说,尽管你的主要计算方法属于国家mon,但并非每个组成部分都属于mon。 此处,evaluate Moves and chooseMove are non-monadic, and I ve used let,以显示如何将它们明确纳入do栏。 如果你对这一风格感到安慰,那么你很可能希望使用<代码><$> (aka fmap)和功能构成更简明扼要:

loop :: State SearchState ()
loop = do
  move <- (chooseMove . evaluateMoves) <$> determineMoves
  modify (makeMove move)
  loop




相关问题
Euler Problem in Haskell -- Can Someone Spot My Error

I m trying my hand at Euler Problem 4 in Haskell. It asks for that largest palindrome formed by multiplying two three-digit numbers. The problem was simple enough, and I thought my Haskell-fu was up ...

How does foldr work?

Can anybody explain how does foldr work? Take these examples: Prelude> foldr (-) 54 [10, 11] 53 Prelude> foldr (x y -> (x+y)/2) 54 [12, 4, 10, 6] 12.0 I am confused about these executions....

Efficient queue in Haskell

How can I efficiently implement a list data structure where I can have 2 views to the head and end of the list, that always point to a head a tail of a list without expensive calls to reverse. i.e: ...

Problem detecting cyclic numbers in Haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give): p3 n = n*(n+1) `div` 2 p4 n = n*n p5 n = n*(3*n -1) `div` 2 p6 n = n*(2*n -1) p7 n = n*(5*n -3)...

Ways to get the middle of a list in Haskell?

I ve just started learning about Functional Programming, using Haskel. I m slowly getting through Erik Meijer s lectures on Channel 9 (I ve watched the first 4 so far) and in the 4th video Erik ...

haskell grouping problem

group :: Ord a => [(a, [b])] -> [(a, [b])] I want to look up all pairs that have the same fst, and merge them, by appending all the list of bs together where they have the same a and discarding ...

Closest equivalent to subprocess.communicate in Haskell

I want to do a popen() / python s subprocess.communicate from Haskell - start a program, give it stdin, and get its stdout/stderr. What s the most direct / Haskellish way to do this?

热门标签