jcpetruzza / barbies

BSD 3-Clause "New" or "Revised" License
92 stars 15 forks source link

Add the `Thin` marker type #29

Closed lspitzner closed 4 years ago

lspitzner commented 4 years ago

As discussed in #28.

I haven't tested this fully yet but the following example seems to work fine so far. It depends on an unreleased (and entirely unpublished) feature of the butcher library and does not make use of the Semigroup fields, but it is a good first test:

{-# LANGUAGE ApplicativeDo #-}
import qualified UI.Butcher.Applicative as Bu
import qualified Barbies                as Ba
import qualified Barbies.Bare           as Ba
import           Data.Semigroup (Any, Max, Last)

data Color = Red | Green | Blue deriving (Show, Read)
data MyFlags c f = MyFlags
  { dryrun     :: Ba.Wear c f (Thin Any Bool)
  , verbosity  :: Ba.Wear c f (Thin Max Int)
  , myUIColor  :: Ba.Wear c f (Thin Last Color)
  , exclude    :: Ba.Wear c f [Text]
  }
  deriving Generic

instance Ba.FunctorB     (MyFlags Ba.Covered)
instance Ba.TraversableB (MyFlags Ba.Covered)
instance Ba.BareB        MyFlags

main :: IO ()
main = Bu.mainFromCmdParser $ do -- parser applicative
  let flagParser = MyFlags
        { dryrun    = Any <$> addSimpleBoolFlag "d" ["dryrun"] mempty
        , verbosity = Max <$> addFlagReadParam "v" ["verbosity"] (flagDefault 0)
        , myUIColor =         addFlagReadParam "c" ["color"] mempty
        }
  flags <- Bu.traverseParser flagParser
  pure $ do -- IO monad
    when (dryrun flags) $ do
      putStrLn "I would do important stuff"
      exit 0
    when (verbosity flags>=2) $ do
      putStrLn "program started"
    putStrLn ("imagine this text was colored " ++ show (myUIColor flags))

The flagParser is a barbie covered in a parser applicative (butcher's CmdParser). Fancy stuff :)

jcpetruzza commented 4 years ago

Very nice, thanks!

jcpetruzza commented 4 years ago

Hmmm, it seems CI is not (always?) being ran on PRs. Need to check why is that :disappointed:

Anyway, stack test is failing atm, so we need to give that a look

lspitzner commented 4 years ago

Ah, sorry about that.

The problem is that it can't resolve the Wear TF if the last argument is not known. With

data ParXW a t f = ParXW (Wear t f a)

a could be Thin g x or it could be something else. And the instances (all of them I think) would look different depending on that.

lspitzner commented 4 years ago

Could add a NoThin marker just to fix this case?

data ParXW a t f = ParXW (Wear t f (NoThin a))

type family Wear t f a where
  Wear Bare    f (NoThin a) = a
  Wear Bare    f (Thin g a) = a
  Wear Bare    f a          = a
  Wear Covered f (NoThin a) = f a
  Wear Covered f (Thin g a) = f (g a)
  Wear Covered f a          = f a
  Wear (Param _ t) f a = Wear t f a
  Wear t       _ _ = TypeError …

I can understand if you want to revert and consider the options.

jcpetruzza commented 4 years ago

While something like NoThin could work, it would make it a backwards incompatible change, which I'd like to avoid. We may still find a variation of this idea that works, but in the meantime I reverted the commit, sorry!