Tôi đang cố triển khai sắp xếp bong bóng trên bất kỳ vùng chứa nào có thể di chuyển bằng cách sử dụng đơn lẻ Tardis.Vòng lặp vô hạn trong sắp xếp bong bóng qua Traversable trong Haskell
{-# 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
Sự khác biệt chính giữa bubble
và bubbleTraversable
là việc xử lý của Finished
cờ: Trong bubble
chúng tôi giả định rằng phải nhất yếu tố đã được sắp xếp và thay đổi cờ, nếu các yếu tố bên trái của nó aren' t; trong bubbleTraversable
chúng tôi thực hiện theo cách khác.
Trong khi cố gắng đánh giá mf
trong bubbleTraversable
chương trình nhập một vòng lặp vô hạn trong tham chiếu lười biếng được chứng minh bằng đầu ra ghc <<loop>>
.
Vấn đề có thể là, forM
cố gắng đánh giá các phần tử liên tiếp, trước khi chuỗi đơn sắc diễn ra (đặc biệt là từ forM
là flip traverse
cho danh sách). Có cách nào để giải cứu việc triển khai này không?
Đây là một câu hỏi tuyệt vời, mà tôi không có thời gian để xem xét vào lúc này. Tôi muốn chỉ ra cuộc thảo luận này về phân loại Traversables: https://www.reddit.com/r/haskell/comments/63a4ea/fast_total_sorting_of_arbitrary_traversable/ Nếu bạn chưa biết về nó, có thể bạn có thể lấy một số ý tưởng từ nó . – Carl