Skip to content

Instantly share code, notes, and snippets.

@sjoerdvisscher
Last active April 23, 2025 14:27
Show Gist options
  • Save sjoerdvisscher/dc1ab6b36ba6988d2bcca0face77dc57 to your computer and use it in GitHub Desktop.
Save sjoerdvisscher/dc1ab6b36ba6988d2bcca0face77dc57 to your computer and use it in GitHub Desktop.
Broad search for any `Foldable`
-- Inspired by the level-monad package by Sebastian Fischer
module Lib
( search
) where
import Data.Foldable (fold)
import Data.Monoid (First(..))
newtype Levels m = Levels { levels :: [m] }
instance Monoid m => Semigroup (Levels m) where
Levels xs <> Levels ys = Levels (mempty : merge xs ys)
instance Monoid m => Monoid (Levels m) where
mempty = Levels []
merge :: Semigroup m => [m] -> [m] -> [m]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = x <> y : merge xs ys
search :: Foldable t => (a -> Bool) -> t a -> Maybe a
search f = getFirst . fold . levels . foldMap yield
where yield x = Levels [First $ if f x then Just x else Nothing]
-- Bikeshedding. In a style that I love, but not clearer.
module Lib
( search
) where
import Data.Foldable (fold)
import Data.Monoid (First(..))
import Control.Monad (mfilter)
import Data.Coerce (Coercible, coerce)
newtype Levels m = Levels [m]
instance Monoid m => Semigroup (Levels m) where
Levels xs <> Levels ys = Levels (mempty : merge xs ys)
instance Monoid m => Monoid (Levels m) where
mempty = Levels []
merge :: Semigroup m => [m] -> [m] -> [m]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = x <> y : merge xs ys
bfs :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
bfs f = fold . ala Levels foldMap (pure . f)
search :: Foldable t => (a -> Bool) -> t a -> Maybe a
search f = ala First bfs (mfilter f . pure)
ala :: Coercible m n => (n -> m) -> ((a -> m) -> b -> m) -> (a -> n) -> b -> n
ala _ = coerce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment