dhall-1.42.3: src/Dhall/Syntax/MultiLet.hs
{-# LANGUAGE LambdaCase #-}
{- | Instead of converting explicitly between 'Expr's and 'MultiLet', it might
be nicer to use a pattern synonym:
> pattern MultiLet' :: NonEmpty (Binding s a) -> Expr s a -> Expr s a
> pattern MultiLet' as b <- (multiLetFromExpr -> Just (MultiLet as b)) where
> MultiLet' as b = wrapInLets as b
>
> multiLetFromExpr :: Expr s a -> Maybe (MultiLet s a)
> multiLetFromExpr = \case
> Let x mA a b -> Just (multiLet x mA a b)
> _ -> Nothing
This works in principle, but GHC as of v8.8.1 doesn't handle it well:
https://gitlab.haskell.org/ghc/ghc/issues/17096
This should be fixed by GHC-8.10, so it might be worth revisiting then.
-}
module Dhall.Syntax.MultiLet
( MultiLet(..)
, multiLet
, wrapInLets
) where
import Data.List.NonEmpty (NonEmpty (..))
import Dhall.Syntax.Binding (Binding)
import Dhall.Syntax.Expr (Expr (..))
import qualified Data.List.NonEmpty as NonEmpty
{-| Generate a 'MultiLet' from the contents of a 'Let'.
In the resulting @'MultiLet' bs e@, @e@ is guaranteed not to be a 'Let',
but it might be a @('Note' … ('Let' …))@.
Given parser output, 'multiLet' consolidates @let@s that formed a
let-block in the original source.
-}
multiLet :: Binding s a -> Expr s a -> MultiLet s a
multiLet b0 = \case
Let b1 e1 ->
let MultiLet bs e = multiLet b1 e1
in MultiLet (NonEmpty.cons b0 bs) e
e -> MultiLet (b0 :| []) e
{-| Wrap let-'Binding's around an 'Expr'.
'wrapInLets' can be understood as an inverse for 'multiLet':
> let MultiLet bs e1 = multiLet b e0
>
> wrapInLets bs e1 == Let b e0
-}
wrapInLets :: Foldable f => f (Binding s a) -> Expr s a -> Expr s a
wrapInLets bs e = foldr Let e bs
{-| This type represents 1 or more nested `Let` bindings that have been
coalesced together for ease of manipulation
-}
data MultiLet s a = MultiLet (NonEmpty (Binding s a)) (Expr s a)