"takeWhile"在列表理解中 [英] "takeWhile" within a list comprehension

查看:55
本文介绍了"takeWhile"在列表理解中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有类似以下内容的东西:

I have something like the following:

[bla z|n<-[0..], let z = foo n, z < 42]

问题是,我希望列表理解尽快在 z<42 失败,就好像是一个takeWhile.我知道我可以将其重构为一堆过滤器和地图,但是通过列表理解它会更加优雅.

The thing is, I want the list comprehension to end as soon as z < 42 fails, as if it were a takeWhile. I know I could refactor this into a bunch of filters and maps, but it will be much more elegant with a list comprehension.

将列表推导和takeWhile结合在一起的最优雅的方法是什么?

What is the most elegant way to combine list comprehensions and takeWhile?

推荐答案

由于列表推导不允许这样做,因此我使用 monad 推导并定义了自定义monad进行了一些修改.结果是,以下工作有效:

Since list comprehensions do not allow this, I have hacked a bit using monad comprehensions and defining a custom monad. The outcome of that is that the following works:

example :: [Int]
example = toList [1000 + n 
                 | n <- fromList [0..]
                 , _ <- nonStopGuard (n > 1)
                 , let z = 10*n
                 , _ <- stopGuard (z < 42) ]

-- Output: [1002,1003,1004]

以上内容作为常规列表理解,但具有两种不同的防护措施. nonStopGuard 用作常规的防护措施,只是需要一种奇怪的语法.相反, stopGuard 会做更多的事情:一旦变为false,它就会停止上一个生成器中的其他选择(例如<-[0 ..]).).

The above works as a normal list comprehension, but has two different kinds of guard. A nonStopGuard works as a regular guard, except for requiring a bizarre syntax. A stopGuard instead does something more: as soon as it become false, it stops further choices in the previous generators (such as <-[0..]) to be considered.

我写的小图书馆如下所示:

The small library I wrote is shown below:

{-# LANGUAGE DeriveFunctor, MonadComprehensions #-}
import Control.Monad
import Control.Applicative

data F a = F [a] Bool
  deriving (Functor, Show)

上面的 Bool stop 位,表示我们必须 stop 考虑其他选择.

The Bool above is a stop bit, signaling we must stop considering further choices.

instance Applicative F where pure = return; (<*>) = ap
instance Monad F where
   return x = F [x] False
   F [] s      >>= _ = F [] s
   F (x:xs) sx >>= f = F (ys ++ zs) (sx || sy || sz)
      where 
      F ys sy = f x
      F zs sz = if sy then F [] False else F xs sx >>= f

f x 发出停止信号时,最后一个 if 将丢弃 xs 部分.

The last if will discard the xs part when f x signals to stop.

nonStopGuard :: Bool -> F ()
nonStopGuard True  = F [()] False
nonStopGuard False = F []   False

常规警卫从不发出停车信号.它只提供一个或零个选择.

A regular guard never signals to stop. It just provides one or zero choices.

stopGuard :: Bool -> F ()
stopGuard True  = F [()] False
stopGuard False = F [] True

当出现错误时,停车警卫会发出信号通知停车.

A stopping guard instead signals to stop as soon as it becomes false.

fromList :: [a] -> F a
fromList xs = F xs False

toList :: F a -> [a]
toList (F xs _) = xs

最后警告:我不确定我的monad实例是否定义了实际的monad,即它是否满足monad法律.

Last caveat: I'm not completely sure my monad instance defines an actual monad, i.e. whether it satisfies the monad laws.

根据@icktoofay的建议,我编写了一些快速检查测试:

Following the suggestion of @icktoofay, I wrote a few quickcheck tests:

instance Arbitrary a => Arbitrary (F a) where
   arbitrary = F <$> arbitrary <*> arbitrary

instance Show (a -> b) where
   show _ = "function"

prop_monadRight :: F Int -> Bool
prop_monadRight m =
   (m >>= return) == m

prop_monadLeft :: Int -> (Int -> F Int) -> Bool
prop_monadLeft x f =
   (return x >>= f) == f x

prop_monadAssoc :: F Int -> (Int -> F Int) -> (Int -> F Int) -> Bool
prop_monadAssoc m f g =
   ((m >>= f) >>= g)
   ==
   (m >>= (\x -> f x >>= g))

运行100000个测试没有发现反例.因此,上面的 F 可能是实际的单子.

Running 100000 tests found no counterexamples. So, it's likely that the above F is an actual monad.

这篇关于"takeWhile"在列表理解中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆