{-# LANGUAGE ScopedTypeVariables #-} module Data.FnList where import Prelude hiding (zip, tail) import Control.Applicative import Data.List.NonEmpty (NonEmpty (..), tail) import Data.Profunctor data FnList a b c = Done c | More a (FnList a b (b -> c)) deriving (Functor) instance Profunctor (FnList a) where dimap _ g (Done c) = Done (g c) dimap f g (More a z) = More a $ dimap f (dimap f g) z arguments :: FnList a b c -> [a] arguments (Done _) = [] arguments (More a z) = a : arguments z answer :: (a -> b) -> FnList a b c -> c answer _ (Done c) = c answer f (More a z) = answer f z (f a) instance Foldable (FnList a a) where foldMap φ = φ . answer id instance Applicative (FnList a b) where pure = Done Done b <*> c = b <$> c More a z <*> c = More a (flip <$> z <*> c) zip :: FnList a₁ a₁ c₁ -> FnList a₂ a₂ c₂ -> FnList (a₁, a₂) (a₁, a₂) (c₁, c₂) zip (Done b₁) y = Done (b₁, answer id y) zip x (Done b₂) = Done (answer id x, b₂) zip (More a₁ x) (More a₂ y) = More (a₁, a₂) (uncurry (***) <$> zip x y) argumentsL :: Applicative p => (a -> p a') -> FnList a b c -> p (FnList a' b c) argumentsL _ (Done c) = pure (Done c) argumentsL f (More a z) = More <$> f a <*> argumentsL f z singleton :: a -> FnList a b b singleton = More `flip` Done id untraverse :: Applicative f => (a -> f b) -> FnList a b c -> f c untraverse _ (Done c) = pure c untraverse f (More a z) = f a <**> untraverse f z permutations :: FnList a b c -> NonEmpty (FnList a b c) permutations = (:|) <*> tail . go where go (Done c) = pure (Done c) go (More a z) = permutations z >>= \ z' -> More a z' :| fmap (\ (b, f) -> More b (f a)) (holes z') holes :: FnList a b c -> [(a, a -> FnList a b c)] holes (Done _) = [] holes (More a z) = (a, flip More z) : (fmap . fmap . fmap) (More a) (holes z) merge :: Ord a => FnList a b (c -> d) -> FnList a b c -> FnList a b d merge = mergeBy compare mergeBy :: ∀ a b c d . (a -> a -> Ordering) -> FnList a b (c -> d) -> FnList a b c -> FnList a b d mergeBy cmp = go where go :: ∀ b c d . FnList a b (c -> d) -> FnList a b c -> FnList a b d go (Done b) c = b <$> c go b (Done c) = ($ c) <$> b go (More a x) (More b y) = case cmp a b of GT -> More b (go ((.) <$> More a x) y) _ -> More a (go (flip <$> x) (More b y))