There is a function that searches for an attractive fixed point through iteration. Can we generalize it to monadic functions?

Introduction

Fixed points are the arguments of the function that it will not change: f x == x. An example would be (\x -> x^2) 1 == 1- here the fixed point is 1.

Attractive fixed points are those fixed points that can be found by iterating from some starting point. For example, it (\x -> x^2) 0.5will converge to 0, so 0 is an attractive fixed point of this function.

Attractive fixed points can, with luck, come up (and, in some cases, even achieved on this set of steps) from a suitable non-fixed point, iterating the function from this point. In other cases, the iteration will diverge, so there must first be evidence that a fixed point will attract the iteration process. For some functions, the proof is well known.

The code

I embellished some prior art that performs the task neatly. Then I decided to extend the same idea to monadic functions, but no luck. This is the code I have:

module Fix where

-- | Take elements from a list until met two equal adjacent elements. Of those,
--   take only the first one, then be done with it.
--
--   This function is intended to operate on infinite lists, but it will still
--   work on finite ones.
converge :: Eq a => [a] -> [a]
converge = convergeBy (==)

-- \ r a = \x -> (x + a / x) / 2
-- \ -- ^ A method of computing square roots due to Isaac Newton.
-- \ take 8 $ iterate (r 2) 1
-- [1.0,1.5,1.4166666666666665,1.4142156862745097,1.4142135623746899,
-- 1.414213562373095,1.414213562373095,1.414213562373095]
-- \ converge $ iterate (r 2) 1
-- [1.0,1.5,1.4166666666666665,1.4142156862745097,1.4142135623746899,1.414213562373095]

-- | Find a fixed point of a function. May present a non-terminating function
--   if applied carelessly!
fixp :: Eq a => (a -> a) -> a -> a
fixp f = last . converge . iterate f

-- \ fixp (r 2) 1
-- 1.414213562373095

-- | Non-overloaded counterpart to `converge`.
convergeBy :: (a -> a -> Bool) -> [a] -> [a]
convergeBy _ [ ] = [ ]
convergeBy _ [x] = [x]
convergeBy eq (x: xs @(y: _))
    | x `eq` y = [x]
    | otherwise = x : convergeBy eq xs

-- \ convergeBy (\x y -> abs (x - y) < 0.001) $ iterate (r 2) 1
-- [1.0,1.5,1.4166666666666665,1.4142156862745097]

-- | Non-overloaded counterpart to `fixp`.
fixpBy :: (a -> a -> Bool) -> (a -> a) -> a -> a
fixpBy eq f = last . convergeBy eq . iterate f

-- \ fixpBy (\x y -> abs (x - y) < 0.001) (r 2) 1
-- 1.4142156862745097

-- | Find a fixed point of a monadic function. May present a non-terminating
--   function if applied carelessly!
--   TODO
fixpM :: (Eq a, Monad m) => (m a -> m a) -> m a -> m a
fixpM f = last . _ . iterate f

(It can be downloaded at repl. Examples are provided to illustrate.)

Problem

fixpM _. [m a] -> [m a], , converge , . , .

fixpM:

fixpM :: (Eq a, Monad m) => (a -> m a) -> a -> m a
fixpM f x = do
    y <- f x
    if x == y
        then return x
        else fixpM f y

-- \ fixpM (\x -> (".", x^2)) 0.5
-- ("............",0.0)

( .)

- , / , . , , inits .

?

?

, , , , , , , , , .

P.S. , . , .

P.S. 2 , @n-m ( iterate), :

fixpM :: (Eq a, Monad m) => (m a -> m a) -> m a -> m a
fixpM f = collapse . iterate f
  where
    collapse (mx: mxs @(my: _)) = do
        x <- mx
        y <- my
        if x == y
            then return x
            else collapse mxs

iterate, , . , .

P.S. 3 , @n-m, , , :

fixpM :: (Eq a, Monad m) => (m a -> m a) -> m a -> m a
fixpM f = lastM . convergeM . iterate (f >>= \x -> return x )

convergeM :: (Monad m, Eq a) => [m a] -> m [a]
convergeM = convergeByM (==)

convergeByM :: (Monad m, Eq a) => (a -> a -> Bool) -> [m a] -> m [a]
convergeByM _ [ ] = return [ ]
convergeByM _ [mx] = mx >>= \x -> return [x]
convergeByM eq xs = do
    case xs of
        [ ] -> return [ ]
        [mx] -> mx >>= \x -> return [x]
        (mx: mxs @(my: _)) -> do
            x <- mx
            y <- my
            if x `eq` y
                then return [x]
                else do
                    xs <- convergeM mxs
                    return (x:xs)

lastM :: Monad m => m [a] -> m a
lastM mxs = mxs >>= \xs -> case xs of
    [] -> error "Fix.lastM: No last element!"
    xs -> return . head . reverse $ xs

, . , : .

+5

Source: https://habr.com/ru/post/1692450/


All Articles