caseof 0.0.0 → 0.0.1
raw patch · 3 files changed
+50/−23 lines, 3 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- CaseOf: nameAsValue :: Name -> Q Name
+ CaseOf: mapCaseOf :: Name -> Q Exp
Files
- README.md +10/−21
- caseof.cabal +1/−1
- src/CaseOf.hs +39/−1
README.md view
@@ -3,6 +3,9 @@ A simple way to query constructors, like cases but slightly more concise. +Prisms from the lens package can also manage this, but this is a bit+simpler.+ Aimed at sum types with many constructors: ``` haskell@@ -23,6 +26,13 @@ Just (1,'a') ``` +There is a "map" over a constructor:++``` haskell+> $(mapCaseOf 'Left) succ (Left 3)+Left 4+```+ There is a combinator which calls your function with n arguments, or passes the whole value to an "else" clause. @@ -30,27 +40,6 @@ > $(caseOf 'Woo) (\x y -> show x ++ show y) (const "") (Wibble 5) "" ```--This allows them to be nested:--```haskell-> $(caseOf 'Woo) (\x y -> show x ++ show y) (const "") (Woo 5 'a')-"5'a'"-> $(caseOf 'Woo) (\x y -> show x ++ show y) ($(caseOf 'Wibble) show (const "")) (Woo 5 'a')-"5'a'"-```--What's the point of `caseOf`? To more easily dispatch on functions:--```haskell-handleHuman name age = ...-handleMachine id = ..-handleWithDefault def =- $(caseOf 'Human) handleHuman .- $(caseOf 'Machine) handleMachine def-```--This applies to any kind of "case" that you'd like to refactor into a function. ## Use in your project
caseof.cabal view
@@ -1,5 +1,5 @@ name: caseof-version: 0.0.0+version: 0.0.1 synopsis: Combinators for casing on constructors description: Template-Haskell-based combinators that let you select on constructors. homepage: https://github.com/chrisdone/caseof#readme
src/CaseOf.hs view
@@ -2,8 +2,15 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TemplateHaskell #-} -module CaseOf where+-- | Template-Haskell-based combinators that let you select on constructors. +module CaseOf+ (isCaseOf+ ,maybeCaseOf+ ,mapCaseOf+ ,caseOf)+ where+ import Language.Haskell.TH import Language.Haskell.TH.Syntax @@ -34,6 +41,37 @@ ]) _ -> fail ("Invalid data constructor " ++ pprint input) where+ varI i = VarE (mkName ("v" ++ show i))+ patI i = VarP (mkName ("v" ++ show i))+ arity (ForallT _ _ t) = arity t+ arity (AppT (AppT ArrowT _) y) = 1 + arity y+ arity _ = 0++-- | Apply a function to the slots of a constructor, if it matches,+-- otherwise identity.+mapCaseOf :: Name -> Q Exp+mapCaseOf input = do+ name <- nameAsValue input+ info <- reify name+ case info of+ DataConI _ ty _ ->+ pure+ (LamE+ [VarP f]+ (LamCaseE+ [ Match+ (ConP name (map patI [1 .. arity ty]))+ (NormalB+ (AppE+ (ConE name)+ (foldl AppE (VarE f) (map varI [1 .. arity ty]))))+ []+ , Match (VarP this) (NormalB (VarE this)) []+ ]))+ _ -> fail ("Invalid data constructor " ++ pprint input)+ where+ f = mkName "f"+ this = mkName "this" varI i = VarE (mkName ("v" ++ show i)) patI i = VarP (mkName ("v" ++ show i)) arity (ForallT _ _ t) = arity t