aboutsummaryrefslogtreecommitdiff
path: root/src/Control/FAlternative.hs
blob: 473b3df5cfdf89cf694095092d95ddb7765eac73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
module Control.FAlternative where

import Data.List.NonEmpty (NonEmpty(..))


data Fallible = Fallible | Infallible
  deriving (Show)

data SFallible fail where
  SFallible :: SFallible 'Fallible
  SInfallible :: SFallible 'Infallible

class KnownFallible fail where knownFallible :: SFallible fail
instance KnownFallible 'Fallible where knownFallible = SFallible
instance KnownFallible 'Infallible where knownFallible = SInfallible


infixr 3 <|>>

class (forall fail. Applicative (f fail)) => FAlternative f where
  faempty :: f 'Fallible a
  (<|>>) :: f 'Fallible a -> f fail a -> f fail a
  noFail :: f 'Infallible a -> f fail a
  toFallible :: KnownFallible fail => f fail a -> f 'Fallible a

faasum :: FAlternative f => [f 'Fallible a] -> f fail a -> f fail a
faasum l p = foldr (<|>>) p l

faasum' :: FAlternative f => [f 'Fallible a] -> f 'Fallible a
faasum' l = faasum l faempty

famany :: FAlternative f => f 'Fallible a -> f 'Infallible [a]
famany p = ((:) <$> p <*> noFail (famany p)) <|>> pure []

fasome :: FAlternative f => f 'Fallible a -> f 'Fallible (NonEmpty a)
fasome p = (:|) <$> p <*> noFail (famany p)

faguard :: FAlternative f => Bool -> f 'Fallible ()
faguard True = pure ()
faguard False = faempty

faguardM :: (FAlternative f, Monad (f 'Fallible), KnownFallible fail)
         => f fail Bool -> f 'Fallible ()
faguardM p = toFallible p >>= faguard

faoptional :: FAlternative f => f 'Fallible a -> f 'Infallible (Maybe a)
faoptional p = (Just <$> p) <|>> pure Nothing

facatch :: FAlternative f => f fail a -> f 'Fallible a -> f fail a
facatch = flip (<|>>)