MaximumBy的惯用,monadic版本会是什么样的?

时间:2018-04-26 21:00:18

标签: haskell monads

如何获得有效容器的最大元素,其中要比较的计算属性也会触发效果?

必须有更可读的方式来执行以下操作:

    let images = [
        #imageLiteral(resourceName: "imageOne"),
        #imageLiteral(resourceName: "imageTwo"),
        #imageLiteral(resourceName: "imageThree"),
        #imageLiteral(resourceName: "imageFour"),
        #imageLiteral(resourceName: "ImageFive"),
        #imageLiteral(resourceName: "imageSix")]



    self.theImage.animationImages = images;
    self.theImage.animationDuration = 10.0
    self.theImage.layer.add(rotatePicture, forKey: nil)
    self.theImage.startAnimating()


    UIView.animate(withDuration: 1, animations:{
        self.theImage.frame.origin.y += 440
    }){_ in

        UIView.animateKeyframes(withDuration: 1, delay: 2.25, options: [.autoreverse, .repeat], animations: {
            self.theImage.frame.origin.y -= 490

        })
    }
}

我使用了重载版本而不是非重载latest dir = Turtle.fold (z (ls dir)) Fold.maximum z :: MonadIO m => m Turtle.FilePath -> m (UTCTime, Turtle.FilePath) z mx = do x <- mx d <- datefile x return (d, x) ,但后者似乎更适合ad-hoc属性选择。

如何更有条理地解决类似问题?

3 个答案:

答案 0 :(得分:5)

所以我对龟一无所知;不知道这是否适合海龟生态系统的其他部分。但是既然你在评论中说服我 [DatetimeIndex(['2017-01-02', '2017-01-03', '2017-01-04', '2017-01-05','2017-01-06'], dtype='datetime64[ns]', freq=None), DatetimeIndex(['2017-01-04', '2017-01-05', '2017-01-06', '2017-01-07', '2017-01-08'], dtype='datetime64[ns]', freq=None)] 值得手写,那么我将如何做到这一点:

maximumByM

我通常更喜欢* On版本的东西 - 它采用映射到maximumOnM :: (Monad m, Ord b) => (a -> m b) -> [a] -> m a maximumOnM cmp [x] = return x -- skip the effects if there's no need for comparison maximumOnM cmp (x:xs) = cmp x >>= \b -> go x b xs where go x b [] = return x go x b (x':xs) = do b' <- cmp x' if b < b' then go x' b' xs else go x b xs 可用元素的函数 - 到* By版本 - 它采用直接进行比较的函数。 Ord类似,但类型为maximumByM,但这可能会迫使您为每个Monad m => (a -> a -> m Ordering) -> [a] -> m a重做效果,而我猜测它不是你想要什么。我发现*经常与我想要做的事情以及我想要的性能特征相匹配。

答案 1 :(得分:1)

由于您已熟悉JSON,因此您可能希望了解Fold,这类似。

FoldM

你可以写:

data FoldM m a b =
  -- FoldM step initial extract
  forall x . FoldM (x -> a -> m x) (m x) (x -> m b)

现在,您可以使用maximumOnM :: (Ord b, Monad m) => (a -> m b) -> FoldM m a (Maybe a) maximumOnM f = FoldM combine (pure Nothing) (fmap snd) where combine Nothing a = do f_a <- f a pure (Just (f_a, a)) combine o@(Just (f_old, old)) new = do f_new <- f new if f_new > f_old then pure $ Just (f_new, new) else pure o 在列表(或其他Foldl.foldM容器)上运行折叠。与Foldable类似,Fold有一个FoldM实例,因此您可以将多个有效折叠组合成一个交错其中每个效果并将其结果组合在一起的折叠。

答案 2 :(得分:0)

可以使用reducer包在可折叠程序上运行效果。

我不确定它是否正确,但它利用现有的组合器和实例(Bounded (Maybe a)除外)。

import Data.Semigroup.Applicative (Ap(..))
import Data.Semigroup.Reducer (foldReduce)
import Data.Semigroup (Max(..))
import System.IO (withFile, hFileSize, IOMode(..))

-- | maxLength
--
-- >>> getMax $ maxLength ["abc","a","hello",""]
-- 5
maxLength :: [String] -> (Max Int)
maxLength = foldReduce . map (length)

-- | maxLengthIO
--
-- Note, this runs IO...
--
-- >>> (getAp $ maxLengthIO ["package.yaml", "src/Lib.hs"]) >>= return . getMax
-- Just 1212
--
-- >>> (getAp $ maxLengthIO []) >>= return . getMax
-- Nothing
maxLengthIO :: [String] -> Ap IO (Max (Maybe Integer))
maxLengthIO xs = foldReduce (map (fmap Just . f) xs) where
    f :: String -> IO Integer
    f s = withFile s ReadMode hFileSize

instance Ord a => Bounded (Maybe a) where
    maxBound = Nothing
    minBound = Nothing