如何获得有效容器的最大元素,其中计算属性与之比较也触发效果?
必须有更多可读性的做事方式:
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)
我使用了超载版本,而不是未载荷的maximumBy
,但后者似乎更好地用于临时属性选择。
如何解决类似问题的方法?
,所以我对海龟一无所知;不知道这是否非常适合乌龟生态系统。但是,由于您在评论中说服我maximumByM
值得手工写作,所以这就是我这样做的方式:
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
我通常更喜欢在事物的版本上 *将映射到 Ord
orable元素映射到 *by版本的函数 - 它采用直接进行比较的函数。maximumByM
会相似,但具有类似于Monad m => (a -> a -> m Ordering) -> [a] -> m a
的类型,但这可能会迫使您重做每个a
的效果,我猜这不是您想要的。我发现 *经常与我想做的事情和我想要的性能特征相匹配。
由于您已经熟悉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
具有Applicative
实例,因此您可以将多个有效的折叠结合到一个交织在一起的效果并结合其结果的折叠中。
可以使用还原器软件包对折叠式运行效果。
我不确定它是否正确,但是它利用现有的组合和实例(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