Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I want to repeatedly apply a function simplify' until the result is "stable" (i.e. simplify'(x) == x):

simplify :: Expr -> Expr
simplify expr =
    let iterations = iterate simplify' expr
        neighbours = zip iterations (tail iterations)
        simplified = takeWhile ((a, b) -> a /= b) neighbours
    in  snd $ last ((expr, expr) : simplified)

simplify' :: Expr -> Expr

This seems to be a common problem to me. Is there a more elegant solution?

Update: I found a much simpler solution, but I'm still looking for a more elegant solution :)

simplify expr =
    let next = simplify' expr
    in  if next == expr
        then expr
        else simplify next
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
916 views
Welcome To Ask or Share your Answers For Others

1 Answer

Here's a slight generalization implemented with straightforward pattern matching and recursion. converge searches through an infinite list, looking for two elements in a row which satisfy some predicate. It then returns the second one.

converge :: (a -> a -> Bool) -> [a] -> a
converge p (x:ys@(y:_))
    | p x y     = y
    | otherwise = converge p ys

simplify = converge (==) . iterate simplify'

This makes it easy to for example use approximate equality for the convergence test.

sqrt x = converge (x y -> abs (x - y) < 0.001) $ iterate sqrt' x
    where sqrt' y = y - (y^2 - x) / (2*y) 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...