packages feed

grisette-0.13.0.1: src/Grisette/Internal/TH/Derivation/DeriveToCon.hs

{-# LANGUAGE TemplateHaskell #-}

-- |
-- Module      :   Grisette.Internal.TH.Derivation.DeriveToCon
-- Copyright   :   (c) Sirui Lu 2024
-- License     :   BSD-3-Clause (see the LICENSE file)
--
-- Maintainer  :   siruilu@cs.washington.edu
-- Stability   :   Experimental
-- Portability :   GHC only
module Grisette.Internal.TH.Derivation.DeriveToCon
  ( deriveToCon,
    deriveToCon1,
    deriveToCon2,
  )
where

import Grisette.Internal.Internal.Decl.Core.Data.Class.ToCon
  ( ToCon (toCon),
    ToCon1 (liftToCon),
    ToCon2 (liftToCon2),
  )
import Grisette.Internal.TH.Derivation.Common (DeriveConfig)
import Grisette.Internal.TH.Derivation.ConvertOpCommon
  ( ConvertOpClassConfig
      ( ConvertOpClassConfig,
        convertFieldCombineFun,
        convertFieldFunExp,
        convertFieldResFun,
        convertOpFunNames,
        convertOpInstanceNames,
        convertOpTarget
      ),
    defaultFieldFunExp,
    genConvertOpClass,
  )
import Grisette.Internal.Unified.EvalModeTag (EvalModeTag (C))
import Language.Haskell.TH (Dec, Name, Q, conE)

toConClassConfig :: ConvertOpClassConfig
toConClassConfig =
  ConvertOpClassConfig
    { convertFieldResFun = \v f -> [|$(return f) $(return v)|],
      convertFieldCombineFun = \f args ->
        foldl
          (\acc arg -> [|$(acc) <*> $arg|])
          [|return $(conE f)|]
          $ fmap return args,
      convertFieldFunExp = defaultFieldFunExp ['toCon, 'liftToCon, 'liftToCon2],
      convertOpTarget = C,
      convertOpInstanceNames = [''ToCon, ''ToCon1, ''ToCon2],
      convertOpFunNames = ['toCon, 'liftToCon, 'liftToCon2]
    }

-- | Derive 'ToCon' instance for a data type.
deriveToCon :: DeriveConfig -> Name -> Q [Dec]
deriveToCon deriveConfig = genConvertOpClass deriveConfig toConClassConfig 0

-- | Derive 'ToCon1' instance for a data type.
deriveToCon1 :: DeriveConfig -> Name -> Q [Dec]
deriveToCon1 deriveConfig =
  genConvertOpClass deriveConfig toConClassConfig 1

-- | Derive 'ToCon2' instance for a data type.
deriveToCon2 :: DeriveConfig -> Name -> Q [Dec]
deriveToCon2 deriveConfig =
  genConvertOpClass deriveConfig toConClassConfig 2