packages feed

applicative-splice (empty) → 0.0.0.0

raw patch · 4 files changed

+343/−0 lines, 4 filesdep +basedep +haskell-src-extsdep +haskell-src-metasetup-changed

Dependencies added: base, haskell-src-exts, haskell-src-meta, mtl, syb, template-haskell

Files

+ Control/Applicative/Splice.hs view
@@ -0,0 +1,184 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DisambiguateRecordFields #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE FlexibleContexts #-}++-- | This module defines a quasiquoter for making it easier to program with+-- applicatives and monads.+--+-- = Basic usage+--+-- The 'appl' quasiquoter takes almost any Haskell expression, and expands to the+-- same Haskell expression, wrapped in a call to 'pure'. For example,+--+-- @+--   [appl| 4 + 5 |]+--      -- expands to:+--      pure (4 + 5)+-- @+--+-- Additionally, the expression given to 'appl' may contain "splices". A splice+-- is a dollar sign immediately followed by a parenthesized expression.+-- The parentheses can be dropped if the expression consists of a single+-- identifier. Here are examples of splices.+--+-- @+--   $(f a b)+--   $([0..7])+--   $getLine+-- @+--+-- The syntax for splices are stolen from Template Haskell+-- splices. Therefore whitespaces are not allowed after the dollar sign.+--+-- The expression inside a splice should have the type @f a@ for some+-- 'Applicative' @f@ and some type @a@. The splice itself should be+-- placed in a context where a value of type @a@ is expected. Then 'appl' expands+-- to an applicative expression that "embeds" the result of the applicative+-- action in the pure context. For example,+--+-- @+--   [appl| f $x (4 + $y) |]+--      -- expands to:+--      (\\a b -> f a (4 + b)) \<$> x \<*> y+-- @+--+-- In terms of types, the dollar sign is like a function of type @forall a. f a -> a@,+-- although it is not a real function.+--+-- The type of the 'appl' expression will be in the same applicative as the+-- splices. This also means mutliple splices in the same block must+-- share the same applicative.+--+-- = Special case: functor splices+--+-- When an 'appl' block contains exactly one splice, the type of the expression+-- inside the splice can be @f a@ for any functor @f@, and it doesn't have to be+-- an applicative. The expansion will only contain a call to '<$>', not 'pure'+-- or '<*>'.+--+-- @+--   [appl| (\"Length\", length $m) |]+--      -- expands to:+--      (\\a -> (\"Length\", length a)) \<$> m+-- @+--+-- = Nested splices for monads+--+-- When your applicative is also a monad, you can have splices inside another+-- splice. For example,+--+-- @+--   [appl| $(putStrLn $ "Hello, " ++ $getLine) |]+--      -- expands to:+--      getLine >>= (\\a -> putStrLn $ "Hello, " ++ a)+-- @+--+-- As in this case, no call to '<$>' is generated if the whole 'appl' block+-- consists of a single splice.+module Control.Applicative.Splice+  ( appl+  ) where++import Control.Monad.State+import Control.Monad.Writer+import Data.Generics+import qualified Language.Haskell.Exts as H+import qualified Language.Haskell.Meta as Meta+import qualified Language.Haskell.TH as TH+import qualified Language.Haskell.TH.Quote as TH++data ApplicativeExp var exp+  = AdoJoin [(var, ApplicativeExp var exp)] exp+  -- ado { v0 <- join e0; v1 <- join e1; ...; return eN }+  deriving (Functor)++-- | The applicative-splice quasiquoter.+appl :: TH.QuasiQuoter+appl = TH.QuasiQuoter+  { quoteExp = genExp+  , quotePat = err+  , quoteType = err+  , quoteDec = err+  }+  where+    err _ = fail "This quasiquoter can only be used in an expression"++genExp :: String -> TH.ExpQ+genExp str = do+  e <- case H.parseExpWithMode parseMode str of+    H.ParseOk e -> return e+    H.ParseFailed loc msg -> fail $ show loc ++ ": " ++ msg+  unApplicative $ bimapApplicativeExp Meta.toName Meta.toExp $ quote e+  where+    parseMode = H.defaultParseMode+      { H.extensions = map H.EnableExtension [H.TemplateHaskell]+      }++bimapApplicativeExp+    :: (a -> c)+    -> (b -> d)+    -> ApplicativeExp a b+    -> ApplicativeExp c d+bimapApplicativeExp f g = go+  where+    go (AdoJoin binds body) = AdoJoin (map goBind binds) (g body)+    goBind (var, app) = (f var, go app)++quote :: H.Exp -> ApplicativeExp H.Name H.Exp+quote e0 = evalState (go e0) 0+  where+    go e = do+      (body, binds) <- runWriterT (everywhereM' (mkM onSplice) e)+      return $ AdoJoin binds body++    onSplice (H.SpliceExp splice) = do+      v <- gensym+      e' <- lift $ go e+      tell [(v, e')]+      return $ H.Var $ H.UnQual v+      where+        !e = case splice of+          H.IdSplice str -> H.Var $ H.UnQual $ H.Ident str+          H.ParenSplice x -> x+    onSplice e = return e++    gensym = do+      n <- get+      put $! n + 1+      return $ argVar n++argVar :: Int -> H.Name+argVar = H.Ident . ("applicative_splice_" ++) . show++unApplicative :: ApplicativeExp TH.Name TH.Exp -> TH.ExpQ+unApplicative (AdoJoin (unzip -> (vars, args)) body) = case args of+  [] -> [| pure $(pure body) |]+  first:rest -> foldl mkAp (join $ mkFmap <$> fun <*> unJoin first) rest+  where+    fun = TH.lamE (map TH.varP vars) (pure body)+    mkAp f a = [| $f <*> $(unJoin a) |]+    mkFmap f a+      | isTrivialIdentity f = pure a+      | otherwise = [| $(pure f) <$> $(pure a) |]+    isTrivialIdentity (TH.LamE [TH.VarP v] e) = e == TH.VarE v+    isTrivialIdentity _ = False++unJoin :: ApplicativeExp TH.Name TH.Exp -> TH.ExpQ+unJoin (AdoJoin binds body) = foldr bind (pure body) binds+  where+    bind (v, a) b = [| $(unJoin a) >>= \ $(TH.varP v) -> $b |]++everywhereM' :: (Monad m) => GenericM m -> GenericM m+everywhereM' f x = do +  x' <- f x+  gmapM (everywhereM' f) x'++_view :: TH.ExpQ -> TH.ExpQ+_view eq = do+  e <- eq+  let str = TH.pprint e+  [| putStrLn str |]
+ LICENSE view
@@ -0,0 +1,121 @@+Creative Commons Legal Code++CC0 1.0 Universal++    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED+    HEREUNDER.++Statement of Purpose++The laws of most jurisdictions throughout the world automatically confer+exclusive Copyright and Related Rights (defined below) upon the creator+and subsequent owner(s) (each and all, an "owner") of an original work of+authorship and/or a database (each, a "Work").++Certain owners wish to permanently relinquish those rights to a Work for+the purpose of contributing to a commons of creative, cultural and+scientific works ("Commons") that the public can reliably and without fear+of later claims of infringement build upon, modify, incorporate in other+works, reuse and redistribute as freely as possible in any form whatsoever+and for any purposes, including without limitation commercial purposes.+These owners may contribute to the Commons to promote the ideal of a free+culture and the further production of creative, cultural and scientific+works, or to gain reputation or greater distribution for their Work in+part through the use and efforts of others.++For these and/or other purposes and motivations, and without any+expectation of additional consideration or compensation, the person+associating CC0 with a Work (the "Affirmer"), to the extent that he or she+is an owner of Copyright and Related Rights in the Work, voluntarily+elects to apply CC0 to the Work and publicly distribute the Work under its+terms, with knowledge of his or her Copyright and Related Rights in the+Work and the meaning and intended legal effect of CC0 on those rights.++1. Copyright and Related Rights. A Work made available under CC0 may be+protected by copyright and related or neighboring rights ("Copyright and+Related Rights"). Copyright and Related Rights include, but are not+limited to, the following:++  i. the right to reproduce, adapt, distribute, perform, display,+     communicate, and translate a Work;+ ii. moral rights retained by the original author(s) and/or performer(s);+iii. publicity and privacy rights pertaining to a person's image or+     likeness depicted in a Work;+ iv. rights protecting against unfair competition in regards to a Work,+     subject to the limitations in paragraph 4(a), below;+  v. rights protecting the extraction, dissemination, use and reuse of data+     in a Work;+ vi. database rights (such as those arising under Directive 96/9/EC of the+     European Parliament and of the Council of 11 March 1996 on the legal+     protection of databases, and under any national implementation+     thereof, including any amended or successor version of such+     directive); and+vii. other similar, equivalent or corresponding rights throughout the+     world based on applicable law or treaty, and any national+     implementations thereof.++2. Waiver. To the greatest extent permitted by, but not in contravention+of, applicable law, Affirmer hereby overtly, fully, permanently,+irrevocably and unconditionally waives, abandons, and surrenders all of+Affirmer's Copyright and Related Rights and associated claims and causes+of action, whether now known or unknown (including existing as well as+future claims and causes of action), in the Work (i) in all territories+worldwide, (ii) for the maximum duration provided by applicable law or+treaty (including future time extensions), (iii) in any current or future+medium and for any number of copies, and (iv) for any purpose whatsoever,+including without limitation commercial, advertising or promotional+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each+member of the public at large and to the detriment of Affirmer's heirs and+successors, fully intending that such Waiver shall not be subject to+revocation, rescission, cancellation, termination, or any other legal or+equitable action to disrupt the quiet enjoyment of the Work by the public+as contemplated by Affirmer's express Statement of Purpose.++3. Public License Fallback. Should any part of the Waiver for any reason+be judged legally invalid or ineffective under applicable law, then the+Waiver shall be preserved to the maximum extent permitted taking into+account Affirmer's express Statement of Purpose. In addition, to the+extent the Waiver is so judged Affirmer hereby grants to each affected+person a royalty-free, non transferable, non sublicensable, non exclusive,+irrevocable and unconditional license to exercise Affirmer's Copyright and+Related Rights in the Work (i) in all territories worldwide, (ii) for the+maximum duration provided by applicable law or treaty (including future+time extensions), (iii) in any current or future medium and for any number+of copies, and (iv) for any purpose whatsoever, including without+limitation commercial, advertising or promotional purposes (the+"License"). The License shall be deemed effective as of the date CC0 was+applied by Affirmer to the Work. Should any part of the License for any+reason be judged legally invalid or ineffective under applicable law, such+partial invalidity or ineffectiveness shall not invalidate the remainder+of the License, and in such case Affirmer hereby affirms that he or she+will not (i) exercise any of his or her remaining Copyright and Related+Rights in the Work or (ii) assert any associated claims and causes of+action with respect to the Work, in either case contrary to Affirmer's+express Statement of Purpose.++4. Limitations and Disclaimers.++ a. No trademark or patent rights held by Affirmer are waived, abandoned,+    surrendered, licensed or otherwise affected by this document.+ b. Affirmer offers the Work as-is and makes no representations or+    warranties of any kind concerning the Work, express, implied,+    statutory or otherwise, including without limitation warranties of+    title, merchantability, fitness for a particular purpose, non+    infringement, or the absence of latent or other defects, accuracy, or+    the present or absence of errors, whether or not discoverable, all to+    the greatest extent permissible under applicable law.+ c. Affirmer disclaims responsibility for clearing rights of other persons+    that may apply to the Work or any use thereof, including without+    limitation any person's Copyright and Related Rights in the Work.+    Further, Affirmer disclaims responsibility for obtaining any necessary+    consents, permissions or other rights required for any use of the+    Work.+ d. Affirmer understands and acknowledges that Creative Commons is not a+    party to this document and has no duty or obligation with respect to+    this CC0 or use of the Work.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ applicative-splice.cabal view
@@ -0,0 +1,36 @@+-- Initial applicative-splice.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                applicative-splice+version:             0.0.0.0+synopsis:            Write applicative programs in direct style (generalizes idiom brackets).+description:         This package defines a quasiquoter that lets you write+                     your monadic/applicative programs in direct style, i.e.+                     the style in which you would write it in a+                     language with side effects. Unlike actual side effects,+                     this does not affect purity of the langauge, because it's+                     just a syntactic sugar around the usual (\<$>), (\<*>) and+                     (>>=) functions.+homepage:            https://github.com/takano-akio/applicative-splice+license:             PublicDomain+license-file:        LICENSE+author:              Takano Akio+maintainer:          aljee@hyper.cx+-- copyright:           +category:            Control+build-type:          Simple+-- extra-source-files:  +cabal-version:       >=1.10++source-repository head+  type: git+  location: https://github.com/takano-akio/applicative-splices.git++library+  exposed-modules:     Control.Applicative.Splice+  -- other-modules:       +  -- other-extensions:    +  build-depends:       base >=4.8 && <5, template-haskell, haskell-src-meta,+                       haskell-src-exts, mtl, syb+  -- hs-source-dirs:      +  default-language:    Haskell2010