{-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE DataKinds #-} {- | Rebindable syntax for Variant This module provides @RebindableSyntax@-based do-notation for 'V'. We recommend using 'Data.Variant.VEither' or "Data.Variant.Excepts" instead, which provide proper 'Monad' instances without requiring @RebindableSyntax@. == Do-notation with Variants We can use do-notation with 'V' as we would with other sum types such as 'Maybe' or 'Either'. However, as we cannot have a 'Monad' instance for 'V', we rely on the @RebindableSyntax@ extension to mimic it. The leftmost type is extracted from the Variant with @>>=@ (or @x \<- myVariant@ with do-notation syntax). Variant types are concatenated on the left. Function @foo@ in the following example composes functions returning Variants by using do-notation: > {-# LANGUAGE TypeApplications #-} > {-# LANGUAGE RebindableSyntax #-} > > import Data.Variant > import Data.Variant.Syntax > > import Prelude hiding (head,lookup,(>>=),(>>),return) > import qualified Prelude > import Text.Read > > foo :: String -> V [Integer, ParseError, LookupError Char, HeadError] > foo str = do > c <- head str > r <- lookup c codeMap > parse (r ++ tail str) > > where > codeMap :: [(Char, String)] > codeMap = [ ('x', "0x") > , ('d', "") > ] > > > data ParseError = ParseError deriving Show > > parse :: String -> V [Integer,ParseError] > parse s = case readMaybe s of > Just i -> V @Integer i > Nothing -> V ParseError > > data HeadError = ListWasEmpty deriving Show > > head :: [a] -> V [a,HeadError] > head [] = toVariantAt @1 ListWasEmpty > head (x:_) = toVariantAt @0 x > > data LookupError k = KeyWasNotPresent k deriving Show > > lookup :: Eq k => k -> [(k,v)] -> V [v,LookupError k] > lookup k vs = case Prelude.lookup k vs of > Just v -> toVariantAt @0 v > Nothing -> toVariantAt @1 (KeyWasNotPresent k) Test: > > foo "d10" > V @Integer 10 > > > foo "x10" > V @Integer 16 > > > foo "u10" > V @(LookupError Char) (KeyWasNotPresent 'u') > > > foo "" > V @HeadError ListWasEmpty > > > foo "d10X" > V @ParseError ParseError -} module Data.Variant.Syntax ( (>>=) , (>>) , return ) where import Data.Variant import Data.Variant.Types import GHC.TypeLits import Prelude hiding ((>>=),(>>),return) (>>=) :: forall x xs ys. ( KnownNat (Length ys) ) => V (x ': xs) -> (x -> V ys) -> V (Concat ys xs) >>= :: forall x (xs :: [*]) (ys :: [*]). KnownNat (Length ys) => V (x : xs) -> (x -> V ys) -> V (Concat ys xs) (>>=) = V (x : xs) -> (x -> V ys) -> V (Concat ys xs) forall x (xs :: [*]) (ys :: [*]). KnownNat (Length ys) => V (x : xs) -> (x -> V ys) -> V (Concat ys xs) bindVariant (>>) :: V xs -> V ys -> V (Concat ys xs) >> :: forall (xs :: [*]) (ys :: [*]). V xs -> V ys -> V (Concat ys xs) (>>) = V xs -> V ys -> V (Concat ys xs) forall (xs :: [*]) (ys :: [*]). V xs -> V ys -> V (Concat ys xs) constBindVariant return :: x -> V '[x] return :: forall x. x -> V '[x] return = x -> V '[x] forall x. x -> V '[x] variantFromValue