Tardis 모나드를 사용하여 모든 통과 컨테이너에 버블 정렬을 구현하려고합니다.거품의 무한 루프가 하스켈의 Traversable을 넘어갑니다
{-# LANGUAGE TupleSections #-}
module Main where
import Control.DeepSeq
import Control.Monad.Tardis
import Data.Bifunctor
import Data.Traversable
import Data.Tuple
import Debug.Trace
newtype Finished = Finished { isFinished :: Bool }
instance Monoid Finished where
mempty = Finished False
mappend (Finished a) (Finished b) = Finished (a || b)
-- | A single iteration of bubble sort over a list.
-- If the list is unmodified, return 'Finished' 'True', else 'False'
bubble :: Ord a => [a] -> (Finished, [a])
bubble (x:y:xs)
| x <= y = bimap id (x:) (bubble (y:xs))
| x > y = bimap (const $ Finished False) (y:) (bubble (x:xs))
bubble as = (Finished True, as)
-- | A single iteration of bubble sort over a 'Traversable'.
-- If the list is unmodified, return 'Finished' 'True', else 'Finished' 'False'
bubbleTraversable :: (Traversable t, Ord a, NFData a, Show a) => t a -> (Finished, t a)
bubbleTraversable t = extract $ flip runTardis (initFuture, initPast) $ forM t $ \here -> do
sendPast (Just here)
(mp, finished) <- getPast
-- For the first element use the first element,
-- else the biggest of the preceding.
let this = case mp of { Nothing -> here; Just a -> a }
mf <- force <$> getFuture -- Tardis uses lazy pattern matching,
-- so force has no effect here, I guess.
traceM "1"
traceShowM mf -- Here the program enters an infinite loop.
traceM "2"
case mf of
Nothing -> do
-- If this is the last element, there is nothing to do.
return this
Just next -> do
if this <= next
-- Store the smaller element here
-- and give the bigger into the future.
then do
sendFuture (Just next, finished)
return this
else do
sendFuture (Just this, Finished False)
return next
where
extract :: (Traversable t) => (t a, (Maybe a, (Maybe a, Finished))) -> (Finished, t a)
extract = swap . (snd . snd <$>)
initPast = (Nothing, Finished True)
initFuture = Nothing
-- | Sort a list using bubble sort.
sort :: Ord a => [a] -> [a]
sort = snd . head . dropWhile (not . isFinished . fst) . iterate (bubble =<<) . (Finished False,)
-- | Sort a 'Traversable' using bubble sort.
sortTraversable :: (Traversable t, Ord a, NFData a, Show a) => t a -> t a
sortTraversable = snd . head . dropWhile (not . isFinished . fst) . iterate (bubbleTraversable =<<) . (Finished False,)
main :: IO()
main = do
print $ sort ([1,4,2,5,2,5,7,3,2] :: [Int]) -- works like a charm
print $ sortTraversable ([1,4,2,5,2,5,7,3,2] :: [Int]) -- breaks
는 bubble
과 bubbleTraversable
사이의 주요 차이점은 Finished
플래그의 처리입니다 : bubble
에서 우리는 가정이 가장 오른쪽의 요소는 이미 정렬되어 바로 왼쪽의 요소가 '때로 믿을 경우, 플래그를 변경 티; bubbleTraversable
에서 우리는 다른 방법으로 그것을합니다.
mf
을 bubbleTraversable
으로 평가하려고하면 프로그램은 ghc 출력 <<loop>>
에 의해 입증 된 것처럼 지연 참조에 무한 루프를 입력합니다.
문제는 forM
는 모나드 체인이 발생 (특히 이후 forM
이 목록의 flip traverse
입니다)되기 전에, 연속적 요소를 평가하기 위해 시도 할 때, 아마. 이 구현을 구할 수있는 방법이 있습니까? 모든
이것은 훌륭한 질문입니다. 지금은 살펴볼 시간이 없습니다. Traversable 정렬에 관한이 토론을 지적하고자합니다 : https://www.reddit.com/r/haskell/comments/63a4ea/fast_total_sorting_of_arbitrary_traversable/ 이미 알고 있지 않다면, 그것으로부터 몇 가지 아이디어를 취할 수 있습니다. . – Carl