Skip to content

Commit

Permalink
Merge pull request #37 from con-kitty/example/sum
Browse files Browse the repository at this point in the history
Add an example for KEnum and KMaybe
  • Loading branch information
zliu41 committed Apr 11, 2022
2 parents d0ac1b0 + f54220f commit 40b673c
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 3 deletions.
8 changes: 5 additions & 3 deletions Categorifier/C/KTypes/KEnum.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ import GHC.Generics (Generic)
import PyF (fmt)

-- | newtype wrapper around Word8 with functions for treating it as its phantom type
-- TODO(greg): if we define this as:
-- newtype KEnum a f = KEnum (f Word8)
-- then do all our troubles go away?
--
-- This is used to wrap enum types (i.e., sum types where all constructors are nullary).
-- It is possible to use an enum type directly without wrapping it in `KEnum`, but only if
-- its `IfCat` instance is not needed (in other words, the enum type may not appear in
-- the result of any @if@ branch).
newtype KEnum f a = KEnum (f Word8) deriving (Generic)

-- | Convert a 'KEnum' to a 'CEnum' by first creating a @'CEnum' 'Proxy'@ to get the type right, and
Expand Down
31 changes: 31 additions & 0 deletions examples/categorifier-c-examples.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,34 @@ executable separate-categorification
, categorifier-unconcat-category
, categorifier-unconcat-integration
default-language: Haskell2010

executable sum-types
hs-source-dirs: sum-types
main-is: Main.hs
other-modules:
F
ghc-options:
-O0
-fexpose-all-unfoldings
-fmax-simplifier-iterations=0
-fno-ignore-interface-pragmas
-fno-omit-interface-pragmas
-Wall
-fplugin Categorifier
-fplugin-opt Categorifier:hierarchy:Categorifier.Hierarchy.UnconCat.hierarchy
-fplugin-opt Categorifier:hierarchy:Categorifier.Hierarchy.ConCat.functionHierarchy
-fplugin-opt Categorifier:hierarchy:Categorifier.Hierarchy.ConCatExtensions.hierarchy
build-depends:
base
, ghc-prim
, concat-classes
, categorifier-c
, categorifier-category
, categorifier-client
, categorifier-concat-extensions-category
, categorifier-concat-extensions-integration
, categorifier-concat-integration
, categorifier-plugin
, categorifier-unconcat-category
, categorifier-unconcat-integration
default-language: Haskell2010
99 changes: 99 additions & 0 deletions examples/sum-types/F.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module F (fCategorified) where

import qualified Categorifier.C.CExpr.Cat as C
import Categorifier.C.CExpr.Cat.TargetOb (TargetOb)
import Categorifier.C.CTypes.CGeneric (CGeneric)
import qualified Categorifier.C.CTypes.CGeneric as CG
import Categorifier.C.CTypes.GArrays (GArrays)
import Categorifier.C.KTypes.C (C)
import Categorifier.C.KTypes.KEnum (KEnum, toKEnum)
import Categorifier.C.KTypes.Sum.Maybe (KMaybe, kJust, kNothing)
import qualified Categorifier.Categorify as Categorify
import Categorifier.Client (deriveHasRep)
import qualified Categorifier.Client
import Data.Int (Int32)
import Data.Word (Word64)
import GHC.Generics (Generic)

data Pet = Cat | Dog | Capybara
deriving (Bounded, Enum, Eq, Ord, Generic)

deriveHasRep ''Pet

-- The following instances are only needed when using `Pet` directly. It isn't needed when
-- wrapping `Pet` in a `KEnum`, as the code below does.

-- instance CGeneric Pet

-- instance GArrays C Pet

-- The `TargetOb` instance for an enum type should be defined via
-- `Categorifier.Client.Rep`, rather than `CG.Rep`.
-- type instance TargetOb Pet = TargetOb (Categorifier.Client.Rep Pet)

data Input = Input
{ iInt32 :: C Int32,
-- | To use an enum type, in general, we need to wrap it with `KEnum`.
--
-- It is possible to use the bare enum type (i.e., `Pet`) directly, as long
-- as the `IfCat` instance is not needed (in other words, `Pet` does not appear
-- in any @if@ branch). In this example, the `IfCat` instance is needed due
-- to `getCompanion`.
--
-- To use `Pet` directly, we also need to define its `CGeneric`, `GArrays`
-- and `TargetOb` instances. See the comment above.
iEnum :: KEnum C Pet
}
deriving (Generic)

deriveHasRep ''Input

instance CGeneric Input

instance GArrays C Input

type instance TargetOb Input = TargetOb (CG.Rep Input ())

data Output = Output
{ oWord64 :: C Word64,
oEnum :: (KEnum C Pet, KEnum C Pet),
-- | To use a `Maybe` type, wrap it with `KMaybe`.
oMaybe :: KMaybe C (C Int32)
}
deriving (Generic)

deriveHasRep ''Output

instance CGeneric Output

instance GArrays C Output

type instance TargetOb Output = TargetOb (CG.Rep Output ())

f :: Input -> Output
f inp =
Output
{ -- Currently, `fromKEnum` is not supported by the plugin. To compare a `KEnum` with
-- an enum type, avoid using `fromKEnum` to convert the former to an enum, rather,
-- use `toKEnum` to convert the latter to a `KEnum`.
oWord64 = if iEnum inp == toKEnum Cat then fromIntegral (iInt32 inp) + 5 else 42,
oEnum = getCompanion (iEnum inp),
oMaybe = if iInt32 inp > 0 then kJust (iInt32 inp * 2) else kNothing
}

getCompanion :: KEnum C Pet -> (KEnum C Pet, KEnum C Pet)
getCompanion p
| p == toKEnum Cat = (p, toKEnum Dog)
| p == toKEnum Dog = (p, toKEnum Capybara)
| otherwise = (p, toKEnum Cat)

fCategorified :: Input `C.Cat` Output
fCategorified = Categorify.expression f
10 changes: 10 additions & 0 deletions examples/sum-types/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import Categorifier.C.Generate (writeCFiles)
import F (fCategorified)

-- This generates /tmp/sum_types.c
main :: IO ()
main = writeCFiles "/tmp" "sum_types" fCategorified

0 comments on commit 40b673c

Please sign in to comment.