metar-0.0.5: src/Data/Aviation/Metar/METARResult.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wall #-}
-- | METAR observation result.
module Data.Aviation.Metar.METARResult where
import Control.Lens (makeClassy, makeClassyPrisms)
import Data.Aviation.Metar.METARError (METARError)
import Data.Eq.Deriving (deriveEq1)
import Data.Functor.Apply (Apply ((<.>)))
import Data.Functor.Bind (Bind ((>>-)))
import Data.Functor.Extend (Extend (duplicated))
import Data.List.NonEmpty (NonEmpty)
import Text.Show.Deriving (deriveShow1)
{- FOURMOLU_DISABLE -}
-- $setup
-- >>> import Data.Aviation.Metar.METARError
-- >>> import Data.Aviation.Metar.METARResult
-- >>> import Data.Functor.Apply ((<.>))
-- >>> import Data.Functor.Bind ((>>-))
-- >>> import Data.Functor.Extend (duplicated)
-- >>> import Data.List.NonEmpty (NonEmpty((:|)))
-- >>> import Network.Stream
{- FOURMOLU_ENABLE -}
-- | Either a METAR value or a non-empty list of everything that went wrong
-- while trying to obtain one.
--
-- >>> METARResultValue "METAR YSSY 280600Z" :: METARResult String
-- METARResultValue "METAR YSSY 280600Z"
-- >>> METARResultFailure (ParseErrorAt "NOAA" "HTTP 404" :| []) :: METARResult String
-- METARResultFailure (ParseErrorAt "NOAA" "HTTP 404" :| [])
data METARResult a
= METARResultFailure (NonEmpty METARError)
| METARResultValue a
deriving (Eq, Show)
makeClassy ''METARResult
makeClassyPrisms ''METARResult
deriveEq1 ''METARResult
deriveShow1 ''METARResult
-- | 'fmap' rewraps 'METARResultValue', preserving the failure constructor.
--
-- >>> fmap (+ 1) (METARResultValue 3 :: METARResult Int)
-- METARResultValue 4
-- >>> fmap (+ 1) (METARResultFailure (ParseErrorAt "src" "why" :| []) :: METARResult Int)
-- METARResultFailure (ParseErrorAt "src" "why" :| [])
instance Functor METARResult where
fmap _ (METARResultFailure es) =
METARResultFailure es
fmap f (METARResultValue a) =
METARResultValue (f a)
-- | '<.>' fails fast on the left; two failures do not accumulate here (only
-- 'Data.Functor.Alt.<!>' accumulates).
--
-- >>> (METARResultValue (+ 1) :: METARResult (Int -> Int)) <.> METARResultValue 3
-- METARResultValue 4
-- >>> (METARResultFailure (ParseErrorAt "src" "why" :| []) :: METARResult (Int -> Int)) <.> METARResultValue 3
-- METARResultFailure (ParseErrorAt "src" "why" :| [])
-- >>> (METARResultValue (+ 1) :: METARResult (Int -> Int)) <.> METARResultFailure (ParseErrorAt "src" "why" :| [])
-- METARResultFailure (ParseErrorAt "src" "why" :| [])
instance Apply METARResult where
METARResultFailure es <.> _ =
METARResultFailure es
METARResultValue f <.> METARResultValue a =
METARResultValue (f a)
METARResultValue _ <.> METARResultFailure es =
METARResultFailure es
-- | 'pure' wraps a value with 'METARResultValue'.
--
-- >>> pure 3 :: METARResult Int
-- METARResultValue 3
instance Applicative METARResult where
pure =
METARResultValue
(<*>) =
(<.>)
-- | Kleisli bind: threads a value forward and short-circuits on failure.
--
-- >>> (METARResultValue 3 :: METARResult Int) >>- (\x -> METARResultValue (x + 1))
-- METARResultValue 4
-- >>> (METARResultFailure (ParseErrorAt "src" "why" :| []) :: METARResult Int) >>- (\x -> METARResultValue (x + 1))
-- METARResultFailure (ParseErrorAt "src" "why" :| [])
instance Bind METARResult where
METARResultFailure es >>- _ =
METARResultFailure es
METARResultValue a >>- f =
f a
-- | 'Monad' inherits from 'Bind' and 'Applicative'.
--
-- >>> (METARResultValue 3 :: METARResult Int) >>= (\x -> METARResultValue (x + 10))
-- METARResultValue 13
instance Monad METARResult where
return =
pure
(>>=) =
(>>-)
-- | Folding contributes the value once for 'METARResultValue', zero times for failure.
--
-- >>> foldr (+) 0 (METARResultValue 5 :: METARResult Int)
-- 5
-- >>> foldr (+) 0 (METARResultFailure (ParseErrorAt "src" "why" :| []) :: METARResult Int)
-- 0
instance Foldable METARResult where
foldr f z (METARResultValue a) =
f a z
foldr _ z (METARResultFailure _) =
z
-- | 'traverse' commutes 'METARResult' with an inner effect.
--
-- >>> traverse Just (METARResultValue 3 :: METARResult Int)
-- Just (METARResultValue 3)
-- >>> traverse Just (METARResultFailure (ParseErrorAt "src" "why" :| []) :: METARResult Int)
-- Just (METARResultFailure (ParseErrorAt "src" "why" :| []))
instance Traversable METARResult where
traverse f (METARResultValue a) =
METARResultValue <$> f a
traverse _ (METARResultFailure es) =
pure (METARResultFailure es)
-- | 'duplicated' nests a value inside a second layer.
--
-- >>> duplicated (METARResultValue 3 :: METARResult Int)
-- METARResultValue (METARResultValue 3)
-- >>> duplicated (METARResultFailure (ParseErrorAt "src" "why" :| []) :: METARResult Int)
-- METARResultFailure (ParseErrorAt "src" "why" :| [])
instance Extend METARResult where
duplicated (METARResultValue a) =
METARResultValue (METARResultValue a)
duplicated (METARResultFailure es) =
METARResultFailure es