cognimeta-utils (empty) → 0.1.0
raw patch · 41 files changed
+3435/−0 lines, 41 filesdep +QuickCheckdep +arraydep +basesetup-changed
Dependencies added: QuickCheck, array, base, bytestring, cognimeta-utils, collections-api, comonad-transformers, containers, data-lens, data-lens-fd, data-lens-template, deepseq, ghc-prim, mtl, primitive, stm, tagged, template-haskell, transformers
Files
- LICENSE-2.0.txt +202/−0
- Setup.hs +6/−0
- cognimeta-utils.cabal +112/−0
- exe-src/Main.hs +45/−0
- src/Cgm/Control/Combinators.hs +81/−0
- src/Cgm/Control/Concurrent/Await.hs +40/−0
- src/Cgm/Control/Concurrent/MVar.hs +43/−0
- src/Cgm/Control/Concurrent/NotificationCount.hs +44/−0
- src/Cgm/Control/Concurrent/TThread.hs +135/−0
- src/Cgm/Control/InFunctor.hs +290/−0
- src/Cgm/Control/Monad/State.hs +111/−0
- src/Cgm/Control/Profile.hs +37/−0
- src/Cgm/Data/Array.hs +292/−0
- src/Cgm/Data/Bool.hs +6/−0
- src/Cgm/Data/Either.hs +62/−0
- src/Cgm/Data/Empty.hs +11/−0
- src/Cgm/Data/Functor.hs +27/−0
- src/Cgm/Data/Functor/Sum.hs +24/−0
- src/Cgm/Data/Len.hs +134/−0
- src/Cgm/Data/List.hs +105/−0
- src/Cgm/Data/LongWord.hs +28/−0
- src/Cgm/Data/MapMultiset.hs +38/−0
- src/Cgm/Data/Maybe.hs +55/−0
- src/Cgm/Data/Monoid.hs +39/−0
- src/Cgm/Data/Multiset.hs +34/−0
- src/Cgm/Data/NEList.hs +29/−0
- src/Cgm/Data/Nat.hs +35/−0
- src/Cgm/Data/Nat/Base.hs +177/−0
- src/Cgm/Data/Nat/Constants.hs +86/−0
- src/Cgm/Data/SortedPair.hs +34/−0
- src/Cgm/Data/Structured.hs +79/−0
- src/Cgm/Data/Structured/Derive.hs +176/−0
- src/Cgm/Data/Super.hs +69/−0
- src/Cgm/Data/Tagged.hs +96/−0
- src/Cgm/Data/Typeable.hs +19/−0
- src/Cgm/Data/Word.hs +121/−0
- src/Cgm/Data/WordN.hs +234/−0
- src/Cgm/Prelude.hs +70/−0
- src/Cgm/System/Endian.hs +117/−0
- src/Cgm/System/Mem/Alloc.hs +67/−0
- src/Cgm/TH/Label.hs +25/−0
+ LICENSE-2.0.txt view
@@ -0,0 +1,202 @@++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ cognimeta-utils.cabal view
@@ -0,0 +1,112 @@+Name: cognimeta-utils+version: 0.1.0+cabal-version: >= 1.8+build-type: Simple+license: OtherLicense+license-file: "LICENSE-2.0.txt"+copyright: (c) 2010-2012 Cognimeta Inc.+maintainer: Patrick Premont <ppremont@cognimeta.com>+homepage: https://github.com/Cognimeta/cognimeta-utils+package-url:+bug-reports:+synopsis: Utilities for Cognimeta products (such as perdure). API may change often.+description: + These utilities are used by Perdure and other internal Cognimeta products.+ .+ Please do not rely on these APIs. If parts of this are of interest to you please contact+ ppremont@cognimeta.com and we will consider creating a cleaner separate package.+category:+author: Patrick Premont for Cognimeta Inc.+tested-with:+data-files:+data-dir: ""+extra-source-files:+extra-tmp-files:+ +library+ buildable: True+ hs-source-dirs: src+ if arch(i386)+ cpp-options: -DWORDSIZE=32+ if arch(x86_64)+ cpp-options: -DWORDSIZE=64+ extensions: CPP+ exposed-modules:+ Cgm.Control.Combinators+ Cgm.Control.Concurrent.Await+ Cgm.Control.Concurrent.MVar+ Cgm.Control.Concurrent.NotificationCount+ Cgm.Control.Concurrent.TThread+ Cgm.Control.InFunctor+ Cgm.Control.Monad.State+ Cgm.Control.Profile+ Cgm.Data.Array+ Cgm.Data.Bool+ Cgm.Data.Either+ Cgm.Data.Empty+ Cgm.Data.Functor+ Cgm.Data.Functor.Sum+ Cgm.Data.Len + Cgm.Data.List+ Cgm.Data.LongWord+ Cgm.Data.MapMultiset+ Cgm.Data.Maybe+ Cgm.Data.Monoid+ Cgm.Data.Multiset+ Cgm.Data.NEList+ Cgm.Data.Nat+ Cgm.Data.Nat.Base+ Cgm.Data.Nat.Constants+ Cgm.Data.SortedPair+ Cgm.Data.Structured+ Cgm.Data.Structured.Derive+ Cgm.Data.Super + Cgm.Data.Tagged+ Cgm.Data.Typeable+ Cgm.Data.Word+ Cgm.Data.WordN+ Cgm.TH.Label+ Cgm.Prelude+ Cgm.System.Endian+ Cgm.System.Mem.Alloc+ other-modules: + build-depends:+ base >= 4.5.0.0 && < 5,+ template-haskell >= 2.7.0.0,+ QuickCheck >=2.4.0.1,+ mtl >= 2.1.2,+ transformers >= 0.3.0.0,+ containers >= 0.4.2.1,+ collections-api >= 1.0.0.0,+ bytestring >= 0.9.2.1,+ array >= 0.4.0.0,+ stm >= 2.3,+ ghc-prim >= 0.2.0.0,+ primitive >= 0.4.1,+ tagged >= 0.4.2.1,+ data-lens >= 2.9.0,+ data-lens-fd >= 2.0.2,+ data-lens-template >= 2.1.5,+ comonad-transformers >= 2.1.1.1,+ deepseq >= 1.3.0.0+ ghc-options: -rtsopts -fcontext-stack=80 -O2 -funfolding-use-threshold=24 -pgmP cpphs -optP --cpp+ extensions: ++source-repository head+ type: git+ location: git://github.com/Cognimeta/perdure.git++executable cognimeta-utils+ hs-source-dirs: exe-src+ main-is: Main.hs+ other-modules: + build-depends:+ base >= 4.5.0.0,+ template-haskell >= 2.7.0.0,+ mtl >= 2.1.2,+ QuickCheck >=2.4.0.1,+ cognimeta-utils >= 0.1.0,+ transformers >= 0.3.0.0,+ bytestring >= 0.9.2.1,+ containers >= 0.4.2.1+ ghc-options: -rtsopts -fcontext-stack=80 -fno-warn-duplicate-exports -O2 -funfolding-use-threshold=24 -threaded
+ exe-src/Main.hs view
@@ -0,0 +1,45 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, TypeFamilies, TemplateHaskell #-}++module Main (+ main++) where++import Data.Int+import Data.Word+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString as B+import qualified Test.QuickCheck as QC+import Test.QuickCheck.Arbitrary+import System.Environment+import Language.Haskell.TH+import Cgm.TH.Label++import Cgm.Control.Profile++main :: IO ()+main = getArgs >>= argsMain++argsMain :: [String] -> IO ()+argsMain (x:xs) = maybe invalidArgs ($ xs) $ lookup x mains+argsMain [] = invalidArgs++invalidArgs :: IO ()+invalidArgs = putStrLn $ "Invalid arguments, first argument should be one of " ++ (show $ map fst mains)++mains :: [(String, [String] -> IO ())]+mains = [+ ]
+ src/Cgm/Control/Combinators.hs view
@@ -0,0 +1,81 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++module Cgm.Control.Combinators (+ fk,+ dot2,+ dot2i,+ dup,+ (./),+ (.//),+ (.///),+ (.////),+ Id,+ todo+) where++++-- A combinator like Generics.Pointless.Combinators./\ but generalized from (,) to any binary function.+-- T+-- /\ = fk (,)+{-# INLINE fk #-}+fk :: (x -> y -> b) -> (a -> x) -> (a -> y) -> a -> b+fk b x y a = b (x a) (y a)+-- fk b x y = dup (dot2 b x y)++-- Like '.' but takes two unary functions on the right, and composes them with a binary+-- functions on the left. May be used infix as in: ++ `dot2` show $ show+{-# INLINE dot2 #-}+dot2 :: (a' -> b' -> c) -> (a -> a') -> (b -> b') -> a -> b -> c+dot2 c a' b' a b = c (a' a) (b' b)++-- Like '.' but takes a binary function on the left, and a unary function on the right+-- The unary function is applied to both arguments+{-# INLINE dot2i #-}+dot2i :: (a' -> a' -> b) -> (a -> a') -> a -> a -> b+dot2i b = dup $ dot2 b++{-# INLINE dup #-}+dup :: (a -> a -> b) -> a -> b+dup bin a = bin a a++-- Composes a function with a binary function+-- It is called 'dot' at http://www.haskell.org/haskellwiki/Pointfree and is equivalent to (.) . (.)+infixr 9 ./+{-# INLINE (./) #-}+(./) :: (b -> c) -> (a1 -> a2 -> b) -> a1 -> a2 -> c+f ./ b = (f .) . b++-- Composes a function with a ternary function+infixr 9 .//+{-# INLINE (.//) #-}+(.//) :: (b -> c) -> (a1 -> a2 -> a3 -> b) -> a1 -> a2 -> a3 -> c+f .// t = (f .) ./ t++-- Composes a function with a 4-ary function+infixr 9 .///+{-# INLINE (.///) #-}+(.///) :: (b -> c) -> (a1 -> a2 -> a3 -> a4 -> b) -> a1 -> a2 -> a3 -> a4 -> c+f ./// q = (f .) .// q++-- Composes a function with a 5-ary function+infixr 9 .////+{-# INLINE (.////) #-}+(.////) :: (b -> c) -> (a1 -> a2 -> a3 -> a4 -> a5 -> b) -> a1 -> a2 -> a3 -> a4 -> a5 -> c+f .//// q = (f .) ./// q++type Id a = a -> a++todo = undefined+
+ src/Cgm/Control/Concurrent/Await.hs view
@@ -0,0 +1,40 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Control.Concurrent.Await ( + Async, + await0, + await1, + mapAsync + ) where + +import Control.Concurrent +import Control.Monad + +-- Takes a operation that takes a nullary callback, performs the operation and awaits the callback +await0 :: (IO () -> IO a) -> IO a +await0 kop = do v <- newEmptyMVar + a <- kop (putMVar v ()) + takeMVar v + return a + +type Async a s = (a -> IO ()) -> IO s + +-- Takes a operation that takes a unary callback, performs the operation, awaits the callback, and returns the value +await1 :: Async a () -> IO a +await1 kop = do v <- newEmptyMVar + kop (putMVar v) + takeMVar v + +mapAsync :: (a -> IO b) -> Async a () -> Async b () +mapAsync f async k = async (f >=> k)
+ src/Cgm/Control/Concurrent/MVar.hs view
@@ -0,0 +1,43 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TupleSections #-} + +module Cgm.Control.Concurrent.MVar ( + stateModifyMVar, + stateTModifyMVar, + withNewMVar, + module Control.Concurrent.MVar + ) where + +import Control.Concurrent.MVar +import Control.Applicative +import Control.Monad.State.Strict +import Data.Tuple +import Control.Exception + +stateModifyMVar :: MVar a -> State a b -> IO b +stateModifyMVar v state = modifyMVar v (return . swap . runState state) + +stateTModifyMVar :: MVar a -> StateT a IO b -> IO b +stateTModifyMVar v st = modifyMVar v ((>>= forceState) . fmap swap . runStateT st) where + forceState (a, b) = fmap (, b) $ evaluate a + -- forceState fixes a selector leak. We do not want the mvar to hold a thunk that keeps b alive + -- I no longer understand what I did here. modifyMVar seems already strict in the pair it receives + -- But forcing the state is still not a bad idea... + +-- z must not refer to the MVar t +withNewMVar :: (MVar t -> IO z) -> StateT t IO z +withNewMVar z = StateT $ (>>= \var -> liftA2 (,) (z var) (readMVar var)) . newMVar + +
+ src/Cgm/Control/Concurrent/NotificationCount.hs view
@@ -0,0 +1,44 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Control.Concurrent.NotificationCount ( + NotificationCount, + withNotificationCount, + notifying + ) where + +import Data.Word +import Control.Concurrent +import Control.Applicative +import Control.Arrow + +-- Counts required notifications that have not yet been received. When they reach zero, registered actions are called. +type NotificationCount = MVar (Word64, [IO ()]) + +mkNotificationCount :: IO NotificationCount +mkNotificationCount = newMVar (0, []) + +requireNotify :: NotificationCount -> IO () +requireNotify = flip modifyMVar_ $ return . first (+ 1) + +notify :: NotificationCount -> IO () +notify = flip modifyMVar_ $ \(n, ios) -> if n == 1 then const (0,[]) <$> sequence_ ios else return (n - 1, ios) + +whenFullyNotified :: IO () -> NotificationCount -> IO () +whenFullyNotified io = flip modifyMVar_ $ \s@(n, ios) -> if n == 0 then const s <$> io else return (n, io : ios) + +withNotificationCount :: (NotificationCount -> IO a) -> IO () -> IO a +withNotificationCount f k = mkNotificationCount >>= \n -> f n >>= (<$ whenFullyNotified k n) + +notifying :: NotificationCount -> (IO () -> IO a) -> IO a +notifying n kf = requireNotify n >> kf (notify n)
+ src/Cgm/Control/Concurrent/TThread.hs view
@@ -0,0 +1,135 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable, TupleSections #-} + +module Cgm.Control.Concurrent.TThread ( + run2, + runWithDeamon + ) where + +import Prelude hiding (catch) +import Data.IntMap +import Data.Typeable +import Control.Exception +import Control.Monad +import Control.Applicative +import Control.Concurrent +import Control.Concurrent.STM +import Cgm.Control.Combinators +import Cgm.Data.Bool + +data Task n a = Task n ((Task n a -> IO ()) -> IO (a -> a)) +data State n a = State {val :: a, nextId :: Int, threads :: IntMap (n, ThreadId, Bool), forcedCancel :: Bool} + +data Abort = Abort deriving (Show, Typeable) +instance Exception Abort -- Not exported since it should not be thrown by anyone else +-- Could malicious code still throw it, by catching it as SomeException, unpacking the exitential, and using throwTo on +-- itself (myThreadId) or some other thread which has leaked its identity? + +-- When a task completes, it applies a transition function to the candidate return value. Whenever the cancel predicate is +-- true for that value, or if a forced cancellation has been triggerred by an exception in a child thread or an abort request +-- in the parent, then all tasks that have not yet been cancelled are cancelled. Tasks starting will start cancelled if +-- the cancel predicate is true on the current value, or if forced cancellation has been triggerred. +-- Users wil probably want to ensure that once the cancel predicate becomes true, it never becomes false again. +-- This function should not be used with asynchronous exceptions in the parent thread (beyond the Abort exception +-- that may be thrown by an outer invocation of this function). Any unhandled exception in a child will be rethrown (wrapped) +-- in the parent, after all children have been cancelled and have completed. The user should only rely on this behavior +-- to handle unexepected exceptions. Other exceptions should be caught and transformed into a value in the children, so +-- that the cancellation predicate can determine if cancellation is appropriate, and that the result transformation function +-- can determine the appropriate result (the caller of run can transform back some values into exceptions). +run :: forall n a. [Task n a] -> a -> (a -> Bool) -> IO a +run tasks initial cancel = newChan >>= run' where + run' c = foldM (flip startTransition) (State initial 0 Data.IntMap.empty False) tasks >>= handler where + handler s = do + state'@(State a _ ts _) <- readChan c >>= ($ s) + bool (handler state') (return a) $ Data.IntMap.null ts + startTransition :: Task n a -> State n a -> IO (State n a) + startTransition (Task n f) (State a i ts fc) = do + t <- forkIO (f (writeChan c . startTransition) >>= writeChan c . endTransition) + let cancelT = fc || cancel a + when cancelT $ throwTo t Abort + return $ State a (i+1) (insert i (n, t, cancelT) ts) fc where + endTransition :: (a -> a) -> State n a -> IO (State n a) + endTransition af (State a next ts fc) = do + let ts' = delete i ts + let a' = af a + ts'' <- bool (return ts') (foldWithKey cancelNonCancelled (return ts') ts') $ not fc && cancel a' + return (State a' next ts' fc) where + cancelNonCancelled :: Int -> (n, ThreadId, Bool) -> Id (IO (IntMap (n, ThreadId, Bool))) + cancelNonCancelled i (n, t, x) = if x then id else (>>= (<$ throwTo t Abort) . adjust (const (n, t, True)) i) + +-- A task represented as pair of a description, and an IO of a triple containing: +-- 1) whether to attempt to cancel the other task, +-- 2) our result when we finish first, which the other task will convert into a final result +-- 3) a function from that result of the other task to the final result, to be used only if we finish second +type Task2 c a b = (String, IO (Task2Result c a b)) +type Task2Result c a b = ((Bool, a), b -> c) + +data UnexpectedTaskException = UnexpectedTaskException Bool String SomeException deriving (Show, Typeable) +data ConcurrentExceptions = ConcurrentExceptions SomeException SomeException deriving (Show, Typeable) +instance Exception UnexpectedTaskException +instance Exception ConcurrentExceptions + +data PeerTaskException = PeerTaskException deriving (Show, Typeable) +instance Exception PeerTaskException + + +-- Unexpected exceptions in a child will be wrapped in an UnexpectedTaskException, and an asynchronous +-- exception PeerTaskException will be thrown in the other task (if it has not already completed). In that case +-- the PeerTaskException is expected by the run2 method, so it does not have to be handled in the child. +-- If both children return an exception, then both are wrapped and the resulting pair is thrown as a ConcurrentExceptions. +-- Child tasks are required to catch Abort (if the peer requests it), and produce a Task2Result +-- TODO handle Abort in parent + +run2 :: Task2 c a b -> Task2 c b a -> IO c +run2 (n1, task1) (n2, task2) = do + h1@(_, m1) <- forkIOT task1 + h2@(_, m2) <- forkIOT task2 + let w1 = UnexpectedTaskException False n1 + let w2 = UnexpectedTaskException True n2 + join $ atomically $ getEitherJust (firstComplete w2 h2 w1) (firstComplete w1 h1 w2) m1 m2 where + firstComplete :: Wrapper -> ThreadHandles (Task2Result c b a) -> Wrapper -> Either SomeException (Task2Result c a b) -> IO c + firstComplete wl (tl, ml) wf = either ex normal where + ex ef = do + throwTo tl PeerTaskException + atomically (getJust ml) >>= either exl (const $ throw wrappedFirst) where + wrappedFirst = wf ef + exl el = maybe twoExceptions (const $ throw wrappedFirst) (fromException el :: Maybe PeerTaskException) where + twoExceptions = throw $ ConcurrentExceptions (SomeException $ wl el) (SomeException wrappedFirst) + normal ((cancel, intermediate), _) = do + when cancel $ throwTo tl Abort + final <- atomically (getJust ml) >>= either (throw . wl) (return . snd) + return $ final intermediate +type Wrapper = SomeException -> UnexpectedTaskException + +runWithDeamon :: (String, IO c) -> (String, IO ()) -> IO c +runWithDeamon (n1, f1) (n2, f2) = run2 + (n1, handle (\(e::Abort) -> error deamonEnded) f1 >>= \c -> return ((True, c), error deamonEnded)) + (n2, handle (\(e::Abort) -> return ()) f2 >> return ((True, ()), id)) where + deamonEnded = "Deamon ended spontaneously" + +type ThreadHandles a = (ThreadId, STM (Maybe (Either SomeException a))) + +forkIOT :: IO a -> IO (ThreadHandles a) +forkIOT f = do + v <- atomically $ newTVar Nothing + t <- forkIO $ handle (set v . Left) (f >>= set v . Right) + return (t, readTVar v) where + set v = atomically . writeTVar v . Just + +getJust :: STM (Maybe a) -> STM a +getJust = (>>= maybe retry return) + +getEitherJust :: (a -> z) -> (b -> z) -> STM (Maybe a) -> STM (Maybe b) -> STM z +getEitherJust z1 z2 m1 m2 = m1 >>= maybe (m2 >>= maybe retry (return . z2)) (return . z1)
+ src/Cgm/Control/InFunctor.hs view
@@ -0,0 +1,290 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE TemplateHaskell, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, ScopedTypeVariables, GeneralizedNewtypeDeriving, FlexibleContexts, TypeFamilies, TypeOperators #-}++module Cgm.Control.InFunctor (+ Function(..),+ ($*),++ Increasing(..),+ Increasing',+ (:>>=),+ uncheckedIncreasing,+ + StrictlyIncreasing(..),+ StrictlyIncreasing',+ (:>>),+ uncheckedStrictlyIncreasing,+ + InjectionA(..),+ InjectionA',+ uncheckedInjectionA,+ injectionA',++ Injection(..),+ Injection',+ uncheckedInjection,+ injection',+ pairInjection,++ InjectionM(..),+ InjectionM',+ uncheckedInjectionM,+ injectionM',++ Bijection(..),+ Bijection',+ uncheckedBijection,+ pairBijection,+ inv,+ liftAB,++ InjectionACofunctor(..),+ InjectionCofunctor(..),+ InjectionMCofunctor(..),+ ExpFunctor(..),+ IncreasingFunctor(..),+ StrictlyIncreasingFunctor(..),+ + Cofunctor(..),+ functorCofunctorComap,+ Comonoidal(..),+ functorIacomap,+ cofunctorIacomap,+ RevFun(..),+ (:<-),+ + wrapU,+ wrapB,+ liftItI,+ liftIItK,+ liftIItI,+ liftIKtI,+ liftIItII+) where++import Prelude (Ord, (>>=), ($), uncurry)+import Control.Category+import Control.Arrow+import Data.Monoid+import Data.Maybe+import Data.Functor+import Control.Applicative+import Data.Functor.Constant+import Data.Functor.Compose+import Cgm.Control.Combinators++-- Function+-- Laws: f is total++class Category f => Function f where+ apply :: f a b -> a -> b++infixr 0 $*+{-# INLINE ($*) #-}+($*) :: Function f => f a b -> a -> b+($*) = apply++instance Function (->) where + {-# INLINE apply #-}+ apply = id++-- Increasing+-- Additional laws: forall a b. a > b implies f a >= f b+class Function f => Increasing f++newtype Increasing' a b = Increasing' (a -> b) -- could be generalized wrap any f in Function instead of just ->+type a :>>= b = Increasing' a b+uncheckedIncreasing :: (a -> b) -> Increasing' a b+uncheckedIncreasing = Increasing'+instance Category Increasing' where+ id = Increasing' id+ (Increasing' a) . (Increasing' b) = Increasing' $ a . b+instance Function Increasing' where apply (Increasing' f) = f+instance Increasing Increasing'++-- Note: assuming total order, strictly increasing implies Injective, we cold reflect that here++-- StrictlyIncreasing+-- Additional laws: forall a b. a > b implies f a > f b+class Increasing f => StrictlyIncreasing f++newtype StrictlyIncreasing' a b = StrictlyIncreasing' (a -> b)+type a :>> b = StrictlyIncreasing' a b+uncheckedStrictlyIncreasing :: (a -> b) -> StrictlyIncreasing' a b+uncheckedStrictlyIncreasing = StrictlyIncreasing'+instance Category StrictlyIncreasing' where+ id = StrictlyIncreasing' id+ (StrictlyIncreasing' a) . (StrictlyIncreasing' b) = StrictlyIncreasing' $ a . b+instance Function StrictlyIncreasing' where apply (StrictlyIncreasing' f) = f+instance Increasing StrictlyIncreasing'+instance StrictlyIncreasing StrictlyIncreasing'++-- InjectionA+-- Additions laws: "fromJust . unapply f . apply f = id", and unapply is total+-- This leaves unspecified the behavior of unapply on values outside the image of apply.++class Function f => InjectionA f where+ unapply :: f a b -> b -> Maybe a++data InjectionA' a b = InjectionA' !(a -> b) !(b -> Maybe a)+instance Category InjectionA' where+ id = InjectionA' id Just+ f . g = InjectionA' (apply f . apply g) ((>>= unapply g) . unapply f)+instance Function InjectionA' where apply (InjectionA' f _) = f+instance InjectionA InjectionA' where unapply (InjectionA' _ f') = f'++uncheckedInjectionA :: (a -> b) -> (b -> Maybe a) -> InjectionA' a b+uncheckedInjectionA = InjectionA'++injectionA' :: InjectionA f => f a b -> InjectionA' a b+injectionA' f = uncheckedInjectionA (apply f) (unapply f)++-- Injection+-- Additions laws: retract.apply = id+-- This leaves unspecified the behavior of unapply on values outside the image of apply.++class InjectionA f => Injection f where+ retract :: f a b -> b -> a++data Injection' a b = Injection' !(a -> b) !(b -> a)+instance Category Injection' where+ id = Injection' id id+ f . g = Injection' (apply f . apply g) (retract g . retract f)+instance Function Injection' where apply (Injection' f _) = f+instance InjectionA Injection' where unapply (Injection' _ f') = Just . f'+instance Injection Injection' where retract (Injection' _ f') = f'++uncheckedInjection :: (a-> b) -> (b -> a) -> Injection' a b+uncheckedInjection = Injection'++injection' :: Injection f => f a b -> Injection' a b+injection' f = uncheckedInjection (apply f) (retract f)++pairInjection :: (Injection f1, Injection f2) => f1 a1 b1 -> f2 a2 b2 -> Injection' (a1, a2) (b1, b2)+pairInjection f1 f2 = uncheckedInjection (apply f1 *** apply f2) (retract f1 *** retract f2)++-- InjectionM+-- Additions laws: "unapply f b = Nothing" for any b such that forall a, "apply f a \= b"+class InjectionA f => InjectionM f++newtype InjectionM' a b = InjectionM' (InjectionA' a b) deriving (Category, Function, InjectionA)+instance InjectionM InjectionM'++uncheckedInjectionM :: (a-> b) -> (b -> Maybe a) -> InjectionM' a b+uncheckedInjectionM = InjectionM' ./ uncheckedInjectionA++injectionM' :: InjectionM f => f a b -> InjectionM' a b+injectionM' f = uncheckedInjectionM (apply f) (unapply f)+++-- Bijection+-- Laws: "apply f . retract f = id", and the laws of the superclasses++class (Injection f, InjectionM f) => Bijection f++newtype Bijection' a b = Bijection' (Injection' a b) deriving (Category, Function, InjectionA, Injection)+instance InjectionM Bijection'+instance Bijection Bijection'++uncheckedBijection :: (a -> b) -> (b -> a) -> Bijection' a b+uncheckedBijection = Bijection' ./ uncheckedInjection++pairBijection :: (Bijection f1, Bijection f2) => f1 a1 b1 -> f2 a2 b2 -> Bijection' (a1, a2) (b1, b2)+pairBijection = Bijection' ./ pairInjection++inv :: Bijection f => f a b -> Bijection' b a+inv f = uncheckedBijection (retract f) (apply f)++liftAB :: (Bijection g, Applicative f) => g a b -> Bijection' (f a) (f b)+liftAB g = uncheckedBijection (apply g <$>) (retract g <$>)++--++class InjectionACofunctor f where iacomap :: InjectionA g => f b -> g a b -> f a+class InjectionCofunctor f where icomap :: Injection g => f b -> g a b -> f a+class InjectionMCofunctor f where imcomap :: InjectionM g => f b -> g a b -> f a++class ExpFunctor f where bmap :: Bijection g => g a b -> f a -> f b++class IncreasingFunctor f where incmap :: Increasing g => g a b -> f a -> f b+class StrictlyIncreasingFunctor f where sincmap :: StrictlyIncreasing g => g a b -> f a -> f b+ +-----+ +instance (Applicative a, InjectionACofunctor c) => InjectionACofunctor (Compose a c) where + iacomap (Compose c) i = Compose $ iacomap <$> c <*> pure i+ +-----+ +class Cofunctor f where+ infixr 4 >$<+ (>$<) :: f b -> (a -> b) -> f a+ +newtype RevFun b a = RevFun {getRevFun :: a -> b} deriving Monoid+type (:<-) = RevFun -- until deriveStructure can accept a type operator+instance Cofunctor (RevFun b) where + {-# INLINE (>$<) #-}+ (RevFun g) >$< f = RevFun $ g . f+instance Cofunctor (Constant a) where + {-# INLINE (>$<) #-}+ (Constant a) >$< f = Constant a +instance (Functor f, Cofunctor c) => Cofunctor (Compose f c) where + {-# INLINE (>$<) #-}+ (>$<) = functorCofunctorComap -- TODO: cleanup: There is an alternative defintion so a newtype would be required to indicate which is desired+ +functorCofunctorComap :: (Functor f, Cofunctor c) => (Compose f c) b -> (a -> b) -> (Compose f c) a+functorCofunctorComap (Compose c) abf = Compose $ (>$< abf) <$> c++-- See definition of Monoidal in http://strictlypositive.org/IdiomLite.pdf+-- If the superclass is changed to Cofunctor (or an exponential functor), it seems the Monoidal laws can be adapted.+-- The munit and mpair methods here would be the special case where the cofunctor is (_ -> m) for some monoid m.+-- Maybe we could move the operations to a superclass with no laws, and have empty Monoidal/Comonoidal classes+-- that derive it and just introduce the laws.+class Comonoidal f where + munit :: f ()+ mpair :: f a -> f b -> f (a, b)+ +instance Monoid m => Comonoidal (RevFun m) where+ munit = mempty+ mpair (RevFun fa) (RevFun fb) = RevFun $ uncurry $ mappend `dot2` fa $ fb+instance Monoid m => Comonoidal (Constant m) where+ munit = Constant mempty+ mpair (Constant fa) (Constant fb) = Constant $ mappend fa fb+instance (Applicative a, Comonoidal c) => Comonoidal (Compose a c) where+ munit = Compose $ pure munit+ mpair (Compose a) (Compose b) = Compose $ mpair <$> a <*> b++-- TODO rename to unsafe+{-# INLINE functorIacomap #-}+functorIacomap :: (Functor f, InjectionA g) => f b -> g a b -> f a+functorIacomap f g = (fromJust . unapply g) <$> f+{-# INLINE cofunctorIacomap #-}+cofunctorIacomap :: (Cofunctor f, InjectionA g) => f b -> g a b -> f a+cofunctorIacomap f g = f >$< apply g++-----++wrapU :: (Bijection og, Function i1g) => og o o' -> i1g i1 i1' -> (i1' -> o') -> i1 -> o+wrapU o i1 f = retract o . f . (i1 $*)+wrapB :: (Bijection og, Function i1g, Function i2g) => og o o' -> i1g i1 i1' -> i2g i2 i2' -> (i1' -> i2' -> o') -> i1 -> i2 -> o+wrapB o i1 i2 f = retract o ./ dot2 f (i1 $*) (i2 $*)++-- We cannot express sufficiently general type. Those functions are rarely useful.+liftItI b f = retract b . f . apply b+liftIItK b f = dot2i f (apply b)+liftIItI b f = retract b ./ liftIItK b f+liftIKtI b f = retract b ./ dot2 f (apply b) id+liftIItII b f = (retract b *** retract b) ./ liftIItK b f+
+ src/Cgm/Control/Monad/State.hs view
@@ -0,0 +1,111 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TupleSections, FlexibleInstances, MultiParamTypeClasses #-} + +module Cgm.Control.Monad.State( + StateT(..), + State, + mState, + runState, + focus, + viewState, + partialState, + partialStateE, + eitherState, + maybeState, + toStandardState, + mapStateT, + pairStateT, + module Control.Monad.State.Class, + module Control.Monad.Trans.Class, + module Control.Monad.IO.Class + ) where + +import Control.Applicative +import Control.Monad +import Control.Arrow +import Data.Functor.Identity +import Data.Maybe +import Control.Monad.State.Class +import Control.Monad.Trans.Class +import Control.Monad.IO.Class +import Control.Concurrent.MVar +import qualified Control.Monad.State.Strict as Std + +import Data.Lens hiding (focus) +import Control.Comonad.Trans.Store + +-- | runStateT and runState do not have the usual types: for now we do not make it too easy to discard the precious 'Nothing' +newtype StateT s m a = StateT {runStateT :: s -> m (a, Maybe s)} + +type State s = StateT s Identity +mState :: (s -> (a, Maybe s)) -> State s a +mState = StateT . fmap Identity +runState :: State s a -> s -> (a, Maybe s) +runState = fmap runIdentity . runStateT + +instance Functor m => Functor (StateT s m) where + fmap f = StateT . fmap (fmap $ first f) . runStateT +instance (Functor m, Monad m) => Applicative (StateT s m) where + pure = return + (<*>) = ap +instance Monad m => Monad (StateT s m) where + return = lift . return + (StateT c) >>= fd = StateT $ \s -> + c s >>= \(a, ms) -> -- We are strict in the state. We do as in Control.Monad.Trans.State.Strict (not .Lazy) + let d = runStateT (fd a) + in maybe (d s) (\s' -> liftM (second $ Just . fromMaybe s') $ d s') ms + +instance MonadTrans (StateT s) where + lift = StateT . const . liftM (, Nothing) + +instance MonadIO m => MonadIO (StateT s m) where + liftIO = lift . liftIO + +instance Monad m => MonadState s (StateT s m) where + get = StateT $ return . (, Nothing) + put = StateT . const . return . ((), ) . Just + +focus :: Monad m => Lens t s -> StateT s m a -> StateT t m a +focus l (StateT smas) = StateT $ (\(st, s) -> liftM (second $ fmap st) $ smas s) . runStore . runLens l + +-- | functions st and ts should form a bijection since a StateT t with no changes will become a StateT s with no changes, no matter what st and ts are +viewState :: Monad m => (s -> t, t -> s) -> StateT t m a -> StateT s m a +viewState (st, ts) (StateT tf) = StateT $ liftM (second $ fmap ts) . tf . st + +-- Work on a part of the state, that may not exist for some inputs +partialState :: Monad m => m a -> (s -> Maybe t, t -> s) -> StateT t m a -> StateT s m a +--partialState d (smt, ts) (StateT tf) = get >>= \s -> maybe (lift d) ((>>= \(a, mt) -> maybe (return ()) (put . ts) mt >> return a) . lift . tf) $ smt s +partialState d (smt, ts) t = viewState (\s -> maybe (Left s) Right $ smt s, either id ts) $ eitherState (lift d) t -- note that we use a view 's -> Either s t' + +-- Like partialState, but remembers which path was taken +partialStateE :: Monad m => m a -> (s -> Maybe t, t -> s) -> StateT t m b -> StateT s m (Either a b) +partialStateE d fs t = partialState (liftM Left d) fs (liftM Right t) + +eitherState :: Monad m => StateT s m a -> StateT t m a -> StateT (Either s t) m a +eitherState (StateT sf) (StateT tf) = StateT $ either (liftM (second $ fmap Left) . sf) (liftM (second $ fmap Right) . tf) + +maybeState :: Monad m => m a -> StateT s m a -> StateT (Maybe s) m a +maybeState n s = viewState (maybe (Left ()) Right, either (const Nothing) Just) $ eitherState (lift n) s + +toStandardState :: Monad m => StateT s m a -> Std.StateT s m a +toStandardState (StateT f) = Std.StateT $ \s -> liftM (second $ fromMaybe s) $ f s + +mapStateT :: (m (a, Maybe s) -> n (b, Maybe s)) -> StateT s m a -> StateT s n b +mapStateT f m = StateT $ f . runStateT m + +pairStateT :: Functor m => StateT s (StateT t m) a -> StateT (s, t) m a +pairStateT (StateT sf) = StateT $ \(s, t) -> fmap (\((a, ms), mt) -> (a, combineMaybes s t ms mt)) $ runStateT (sf s) t where + combineMaybes s t ms = maybe (fmap (, t) ms) (Just . (fromMaybe s ms,)) +
+ src/Cgm/Control/Profile.hs view
@@ -0,0 +1,37 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++module Cgm.Control.Profile (+ putCpuTime,+ cpuTimeNF,+ cpuTime+) where++import System.CPUTime+import Control.DeepSeq+import Data.Functor+import Control.Exception++putCpuTime :: String -> IO a -> IO a+putCpuTime s io = cpuTime io >>= \(a, t) -> a <$ (putStrLn $ s ++ " = " ++ show t)++cpuTimeNF :: NFData a => a -> IO (a, Float)+cpuTimeNF f = cpuTime $ evaluate $ (rnf f) `seq` f++cpuTime :: IO a -> IO (a, Float)+cpuTime f = do t0 <- getCPUTime+ a <- f+ t1 <- getCPUTime+ return $ (a, (((fromInteger (t1 - t0)))::Float) / 1e12)++
+ src/Cgm/Data/Array.hs view
@@ -0,0 +1,292 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE ScopedTypeVariables, UnboxedTuples, BangPatterns, MagicHash, TupleSections, TypeFamilies, FlexibleContexts, FlexibleInstances, UndecidableInstances, Rank2Types, EmptyDataDecls #-} + +module Cgm.Data.Array ( + ArrayIx, + Array(..), + ImmArray(..), + STArray(..), + STMkArray(..), + STZArray(..), + PinnedArray(..), + Allocation(..), + newAlignedPinnedWord8Array, + withArrayByteString, + arrayFromByteString, + unsafeWithCastArrayByteString, + Free, + Pinned, + primArrayMatchAllocation, + PrimArray, + runSTPrimArray, + unsafeFreezeSTPrimArray, + STPrimArray, + ArrayRange(..), + fullArrayRange, + skipArrayRange, + headArrayRange, + wordConvArrayRange, + unsafePrimArrayCast, + unsafeSTPrimArrayCast, + mapMArray, + mapMArrayCopy, + mapMArrayCopyImm, + mapImmArray, + mkArrayWith, + ioToST, + primSizeOf, + ST(ST), + module Control.Monad.ST, + module Data.Primitive.Types + ) where + +import Prelude () +import Cgm.Prelude +import GHC.IO( IO(..), ioToST ) +import GHC.ST( ST(..) ) +import GHC.Exts +import GHC.Prim +import qualified Data.ByteString as ByteString +import Data.ByteString.Unsafe +import Foreign.Storable +import Foreign.Ptr +import Control.Monad.ST +import Cgm.Data.Word +import Cgm.Data.Len +import Cgm.System.Mem.Alloc +import Data.Primitive.Types +--import Cgm.System.Endian + +type ArrayIx a = Len (ArrayElem a) Word +type ArrayST a = ST (ArrayState a) + +class Array a where + type ArrayElem a :: * + arrayLen :: a -> ArrayIx a + +class Array a => ImmArray a where + indexArray :: a -> ArrayIx a -> ArrayElem a + +class Array a => STArray a where + type ArrayState a :: * + +-- | STArrays that are instantiable in GCed memory +class STArray a => STMkArray a where + mkArray :: ArrayIx a -> ArrayST a a + +-- | STArrays that can be mutated using zero based indexing +class STArray a => STZArray a where + readArray :: a -> ArrayIx a -> ArrayST a (ArrayElem a) + writeArray :: a -> ArrayIx a -> ArrayElem a -> ArrayST a () + +class Array a => PinnedArray a where + withArrayPtr :: (Ptr (ArrayElem a) -> ArrayIx a -> IO b) -> a -> IO b + +class Allocation f where + newWord8Array :: Len Word8 Word -> ST s (STPrimArray s f Word8) + onAllocation :: (f ~ Free => z) -> (f ~ Pinned => z) -> Tagged f z + +withArrayByteString :: (PinnedArray a, ArrayElem a ~ Word8) => (ByteString.ByteString -> IO b) -> a -> IO b +withArrayByteString f a = flip withArrayPtr a $ \ptr len -> (unsafePackCStringFinalizer ptr (fromIntegral $ getLen len) $ return ()) >>= f + +unsafeWithCastArrayByteString :: forall a b. (PinnedArray a, Prim (ArrayElem a)) => (ByteString.ByteString -> IO b) -> a -> IO b +unsafeWithCastArrayByteString f a = flip withArrayPtr a $ + \ptr len -> (unsafePackCStringFinalizer (castPtr ptr) (fromIntegral (getLen len) * primSizeOf (undefined :: ArrayElem a)) $ return ()) >>= f + +-- Could we avoid the copy or do a memcpy ? Can we access the Ptr of the ByteString ? +arrayFromByteString :: Allocation f => ByteString.ByteString -> PrimArray f Word8 +arrayFromByteString b = mkArrayWith (unsafeLen $ fromIntegral $ ByteString.length b) $ ByteString.index b . fromIntegral . getLen + +arrayToList :: ImmArray a => a -> [ArrayElem a] +arrayToList a = fmap (indexArray a) $ counting $ arrayLen a + +-- TODO remove Prim constraint, by adding method to get byte length of an array +immArrayEq :: (ImmArray a, Eq (ArrayElem a), Prim (ArrayElem a)) => a -> a -> Bool +immArrayEq a b = (arrayLen a == arrayLen b) && (and $ fmap (\i -> indexArray a i == indexArray b i) (counting $ min (arrayLen a) (arrayLen b))) + +--------------------------------------------------------------------------- + +st_ :: (State# s -> State# s) -> ST s () +st_ f = ST $ \s -> (# f s, () #) + +--------------------------------------------------------------------------- + +data Free +data Pinned + +instance Allocation Free where + newWord8Array l = ST $ \s -> case newByteArray# (unI# (fromIntegral $ getLen l)) s of (# s', a #) -> (# s', STPrimArray a #) + onAllocation f p = tag f +instance Allocation Pinned where + newWord8Array l = ST $ \s -> case newPinnedByteArray# (unI# (fromIntegral $ getLen l)) s of (# s', a #) -> (# s', STPrimArray a #) + onAllocation f p = tag p + +newAlignedPinnedWord8Array :: Len Word8 Word -> Len Word8 Word -> ST s (STPrimArray s f Word8) +newAlignedPinnedWord8Array al l = ST $ \s -> + case newAlignedPinnedByteArray# (unI# (fromIntegral $ getLen l)) (unI# (fromIntegral $ getLen al)) s of (# s', a #) -> (# s', STPrimArray a #) + +primArrayMatchAllocation :: forall f f' w. (Allocation f, Allocation f', Prim w) => ArrayRange (PrimArray f w) -> ArrayRange (PrimArray f' w) +primArrayMatchAllocation = (at :: At f) $ onAllocation + ((at :: At f') $ onAllocation id (fullArrayRange . mapImmArray id)) + ((at :: At f') $ onAllocation (fullArrayRange . mapImmArray id) id) + +--------------------------------------------------------------------------- + +primSizeOf :: Prim w => w -> Int +primSizeOf w = I# (sizeOf# w) + +-- | f is either Free or Pinned +data STPrimArray s f w = STPrimArray (MutableByteArray# s) + +instance Eq (STPrimArray s f w) where (STPrimArray a) == (STPrimArray b) = sameMutableByteArray# a b + +instance Prim w => Array (STPrimArray s f w) where + type ArrayElem (STPrimArray s f w) = w + arrayLen (STPrimArray a) = unsafeLen $ fromIntegral $ I# (sizeofMutableByteArray# a `quotInt#` sizeOf# (undefined :: w)) + +instance Prim w => STArray (STPrimArray s f w) where + type ArrayState (STPrimArray s f w) = s + +instance (Allocation f, Prim w) => STMkArray (STPrimArray s f w) where + mkArray l = unsafeSTPrimArrayCast <$> newWord8Array (unsafeLen $ getLen l * fromIntegral (I# (sizeOf# (undefined :: w)))) + +instance Prim w => STZArray (STPrimArray s f w) where + {-# INLINE readArray #-} + readArray (STPrimArray a) i = ST $ readByteArray# a (word2Int# (unW# (getLen i))) + {-# INLINE writeArray #-} + writeArray (STPrimArray a) i w = st_ $ writeByteArray# a (word2Int# (unW# (getLen i))) w + +instance Prim w => PinnedArray (STPrimArray s Pinned w) where + {-# INLINE withArrayPtr #-} + withArrayPtr f arr@(STPrimArray a) = f (Ptr (byteArrayContents# (unsafeCoerce# a))) (arrayLen arr) >>= (<$ (IO $ \s -> (# touch# a s, () #))) + +--------------------------------------------------------------------------- + +-- | f is either Free or Pinned +data PrimArray f w = PrimArray ByteArray# + +instance (Prim w, Eq w) => Eq (PrimArray f w) where (==) = immArrayEq + +instance (Prim w, Show w) => Show (PrimArray f w) where show = show . arrayToList + +instance Prim w => Array (PrimArray f w) where + type ArrayElem (PrimArray f w) = w + arrayLen (PrimArray a) = unsafeLen $ fromIntegral $ I# (sizeofByteArray# a `quotInt#` sizeOf# (undefined :: w)) + +instance Prim w => ImmArray (PrimArray f w) where + {-# INLINE indexArray #-} + indexArray (PrimArray a) i = indexByteArray# a (word2Int# (unW# (getLen i))) + +instance Prim w => PinnedArray (PrimArray Pinned w) where + {-# INLINE withArrayPtr #-} + withArrayPtr f arr@(PrimArray a) = f (Ptr (byteArrayContents# a)) (arrayLen arr) >>= (<$ (IO $ \s -> (# touch# a s, () #))) + +runSTPrimArray :: (forall s . ST s (STPrimArray s f w)) -> PrimArray f w +runSTPrimArray st = runST (st >>= unsafeFreezeSTPrimArray) + +-- | Safe as long as the input array is not written to after this call. Use the safe runSTPrimArray when possible. +unsafeFreezeSTPrimArray :: STPrimArray s f w -> ST s (PrimArray f w) +unsafeFreezeSTPrimArray (STPrimArray a) = ST (\s -> case unsafeFreezeByteArray# a s of (# s', a' #) -> (#s', PrimArray a' #) ) + +--------------------------------------------------------------------------- + +data ArrayRange a = ArrayRange a (ArrayIx a) (ArrayIx a) -- start and size + +instance (ImmArray a, Eq (ArrayElem a), Prim (ArrayElem a)) => Eq (ArrayRange a) where (==) = immArrayEq +instance (ImmArray a, Show (ArrayElem a)) => Show (ArrayRange a) where show = show . arrayToList +instance Array a => Array (ArrayRange a) where + type ArrayElem (ArrayRange a) = ArrayElem a + arrayLen (ArrayRange _ _ len) = len +instance ImmArray a => ImmArray (ArrayRange a) where + indexArray (ArrayRange a s _) i = indexArray a $ s + i +instance STArray a => STArray (ArrayRange a) where + type ArrayState (ArrayRange a) = ArrayState a +instance STZArray a => STZArray (ArrayRange a) where + readArray (ArrayRange a s _) i = readArray a $ i + s + writeArray (ArrayRange a s _) i e = writeArray a (i + s) e + +instance (Prim (ArrayElem a), PinnedArray a) => PinnedArray (ArrayRange a) where + withArrayPtr f (ArrayRange a start sz) = withArrayPtr (\ptr _ -> f (ptr `plusPtrLen` start) sz) a + +{-# INLINE plusPtrLen #-} +plusPtrLen :: forall a b. (Prim a, Integral b) => Ptr a -> Len a b -> Ptr a +plusPtrLen p = plusPtr p . (* primSizeOf (undefined :: a)) . fromIntegral . getLen + +fullArrayRange :: Array a => a -> ArrayRange a +fullArrayRange a = ArrayRange a 0 (arrayLen a) + +skipArrayRange :: Array a => ArrayIx a -> ArrayRange a -> ArrayRange a +skipArrayRange n (ArrayRange a s l) = ArrayRange a (s + n) (l - n) + +headArrayRange :: Array a => ArrayIx a -> ArrayRange a -> ArrayRange a +headArrayRange n (ArrayRange a s l) = ArrayRange a s $ min n l + +-- Can't be an instance of WordConv1 since ArrayRange has the wrong kind +wordConvArrayRange :: WordConv c => Bijection' (ArrayRange (PrimArray f Word)) (ArrayRange (PrimArray f c)) +wordConvArrayRange = uncheckedBijection + (\(ArrayRange a s l) -> ArrayRange (apply wordConv1 a) (apply wordLenB s) (apply wordLenB l)) + (\(ArrayRange a s l) -> ArrayRange (retract wordConv1 a) (retract wordLenB s) (retract wordLenB l)) + +--------------------------------------------------------------------------- + +{-# INLINE unsafeSTPrimArrayCast #-} +unsafeSTPrimArrayCast :: STPrimArray s f w -> STPrimArray s f w' +unsafeSTPrimArrayCast (STPrimArray a) = STPrimArray a + +{-# INLINE unsafePrimArrayCast #-} +unsafePrimArrayCast :: PrimArray f w -> PrimArray f w' +unsafePrimArrayCast (PrimArray a) = PrimArray a + +instance WordConv1 (PrimArray f) where wordConv1 = uncheckedBijection unsafePrimArrayCast unsafePrimArrayCast +instance WordConv1 (STPrimArray s f) where wordConv1 = uncheckedBijection unsafeSTPrimArrayCast unsafeSTPrimArrayCast + +{-# INLINE mapMArray #-} +mapMArray :: STZArray a => (ArrayElem a -> ArrayST a (ArrayElem a)) -> a -> ArrayST a () +mapMArray f a = mapM_ (\i -> readArray a i >>= f >>= writeArray a i) $ counting $ arrayLen a + +-- | The number of elements copied is the minimum of the number of elements in the source and the number of elements in the destination +{-# INLINE mapMArrayCopy #-} +mapMArrayCopy :: (STZArray a, STZArray b, ArrayState a ~ ArrayState b) => (ArrayElem a -> ArrayST a (ArrayElem b)) -> a -> b -> ArrayST a () +mapMArrayCopy f src dest = mapM_ (\i -> readArray src (unsafeLen i) >>= f >>= writeArray dest (unsafeLen i)) $ + counting $ min (getLen $ arrayLen src) (getLen $ arrayLen dest) + +-- | The number of elements copied is the minimum of the number of elements in the source and the number of elements in the destination +{-# INLINE mapMArrayCopyImm #-} +mapMArrayCopyImm :: (ImmArray a, STZArray b) => (ArrayElem a -> ArrayST b (ArrayElem b)) -> a -> b -> ArrayST b () +mapMArrayCopyImm f src dest = mapM_ (\i -> f (indexArray src $ unsafeLen i) >>= writeArray dest (unsafeLen i)) $ + counting $ min (getLen $ arrayLen src) (getLen $ arrayLen dest) + +mkArrayWith :: (Allocation f, Prim a) => Len a Word -> (Len a Word -> a) -> PrimArray f a +mkArrayWith l f = runSTPrimArray $ do + m <- mkArray l + mapM_ (\i -> writeArray m i $ f i) $ counting l + return m + +mapImmArray :: (Allocation f', Prim b, ImmArray r) => (ArrayElem r -> b) -> r -> PrimArray f' b +mapImmArray f src = mkArrayWith (unsafeLen $ getLen $ arrayLen src) (f . indexArray src . unsafeLen . getLen) + +{- + +asSharedByteArray :: Endian w => STPrimArray s f w -> IO (STPrimArray s f Word8) +asSharedByteArray = unsafeSTPrimArrayCast + +{-# INLINE destructivePlatformToLE #-} +destructivePlatformToLE :: (SizedArray (STPrimArray s f w), STZArray (STPrimArray s f w), Endian w) => STPrimArray s f w -> IO (STPrimArray s f w) +destructivePlatformToLE a = a <$ (littleEndianConv >>= maybe (return ()) (\c -> mapMArray (return . c) a)) + +-} +--------------------------------------------------------------------------- + +--instance Show (Buffer a) where show = ($ "") . showListWith showHex . ByteString.unpack . unsafePerformIO . bufferByteString
+ src/Cgm/Data/Bool.hs view
@@ -0,0 +1,6 @@+module Cgm.Data.Bool( + bool + ) where + +bool :: z -> z -> Bool -> z +bool f t c = if c then t else f
+ src/Cgm/Data/Either.hs view
@@ -0,0 +1,62 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TypeOperators #-} + +module Cgm.Data.Either ( + (:|), + isRight, + mkRight, + mkLeft, + boolEither, + fromRight, + throwErrorT, + mapError + ) where + +import Cgm.Control.InFunctor +import Cgm.Data.Bool +import Control.Monad.Error +import Control.Exception +import Control.Arrow + +infixr 2 :| +type a :| b = Either a b + +isRight :: Either a b -> Bool +isRight = either (const False) (const True) + +mkRight :: a :>> Either b a +mkRight = uncheckedStrictlyIncreasing Right +mkLeft :: a :>> Either a b +mkLeft = uncheckedStrictlyIncreasing Left + +boolEither :: a -> b -> Bool -> Either a b +boolEither a b = bool (Left a) (Right b) + +fromRight :: Either a b -> b +fromRight (Left _) = error "fromRight called on Left" +fromRight (Right x) = x + +throwErrorT :: (Show e, MonadIO m) => ErrorT e m a -> m a +throwErrorT = (>>= liftIO . evaluate . either (error . show) id) . runErrorT + +mapError :: Monad m => (e -> e') -> ErrorT e m a -> ErrorT e' m a +mapError e = mapErrorT $ liftM $ left e + + +--filterEither :: (a -> Either b c) -> DList a -> (DList b, DList c) +--filterEither f = foldr (flip add . f) (empty, empty) +-- where add lists = either (\b -> flip fmap1 lists (cons b)) +-- (\c -> flip fmap2 lists (cons c)) +
+ src/Cgm/Data/Empty.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE EmptyDataDecls #-} + +module Cgm.Data.Empty( + onØ, + Ø + ) where + +data Ø + +onØ :: Ø -> a +onØ _ = undefined
+ src/Cgm/Data/Functor.hs view
@@ -0,0 +1,27 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Data.Functor( + mapf, + (<$$>), + module Data.Functor + ) where + +import Data.Functor + +mapf :: Functor f => f a -> (a -> b) -> f b +mapf = flip fmap + +(<$$>) :: Functor f => f a -> (a -> b) -> f b +(<$$>) = flip fmap +
+ src/Cgm/Data/Functor/Sum.hs view
@@ -0,0 +1,24 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TemplateHaskell, TypeFamilies #-} + +module Cgm.Data.Functor.Sum ( + Sum(..) + ) where + +import Cgm.Data.Structured + +newtype Sum a b e = Sum {getSum :: Either (a e) (b e)} + +deriveStructured ''Sum
+ src/Cgm/Data/Len.hs view
@@ -0,0 +1,134 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TemplateHaskell, TypeFamilies, ScopedTypeVariables, BangPatterns, MultiParamTypeClasses, FlexibleContexts, GeneralizedNewtypeDeriving, DeriveFunctor, DeriveDataTypeable #-} + +module Cgm.Data.Len ( + Len, + showLen, + bitLen, + word8, + word16, + word32, + word64, + word, + LgMultiple(..), + unsafeLen, + getLen, + wordLenB, + bitSizeLen, + refineLen, + coarsenLen, + coarseRem, + ceilDivPower2, + roundUpPower2 + ) where + +import Prelude() +import Cgm.Prelude +import Data.Bits +import Control.Category +import Cgm.Data.Tagged +import Cgm.Data.Word +import Cgm.Data.WordN +import Cgm.Control.InFunctor +import Cgm.Data.Structured +import Cgm.Data.Super +import Data.Typeable + +newtype Len u n = Len {getLen :: n} deriving (Ord, Enum, Real, Integral, Num, Eq, Bounded, Functor, Typeable) + +instance Show n => Show (Len u n) where show = show . getLen + +showLen :: forall n u. (Show n, LgMultiple u Bool) => Len u n -> String +showLen (Len n) = show n ++ "_" ++ show ((1::Int) `shiftL` getLgMul (lgMul :: LgMul u Bool)) + +unsafeLen = Len + +bitLen :: Integral a => Len Bool a +bitLen = Len 1 +word8 :: Integral a => Len Word8 a +word8 = Len 1 +word16 :: Integral a => Len Word16 a +word16 = Len 1 +word32 :: Integral a => Len Word32 a +word32 = Len 1 +word64 :: Integral a => Len Word64 a +word64 = Len 1 +word :: Integral a => Len Word a +word = Len 1 + +-- Says that type a's size is a (non-negative) power of 2 multiple of type b's size +newtype LgMul a b = LgMul {getLgMul :: Int} +class LgMultiple a b where lgMul :: LgMul a b +instance LgMultiple Word8 Bool where lgMul = LgMul 3 +instance LgMultiple Word16 Word8 where lgMul = LgMul 1 +instance LgMultiple Word32 Word16 where lgMul = LgMul 1 +instance LgMultiple Word64 Word32 where lgMul = LgMul 1 +-- Reflexive instances +instance LgMultiple Bool Bool where lgMul = id +instance LgMultiple Word8 Word8 where lgMul = id +instance LgMultiple Word16 Word16 where lgMul = id +instance LgMultiple Word32 Word32 where lgMul = id +instance LgMultiple Word64 Word64 where lgMul = id +-- Transitive closure +instance LgMultiple Word16 Bool where lgMul = (at :: At Word8) lgMulTrans +instance LgMultiple Word32 Bool where lgMul = (at :: At Word8) lgMulTrans +instance LgMultiple Word64 Bool where lgMul = (at :: At Word8) lgMulTrans +instance LgMultiple Word32 Word8 where lgMul = (at :: At Word16) lgMulTrans +instance LgMultiple Word64 Word8 where lgMul = (at :: At Word16) lgMulTrans +instance LgMultiple Word64 Word16 where lgMul = (at :: At Word32) lgMulTrans +-- Word instances +instance LgMultiple Word Bool where lgMul = wordLgMul +instance LgMultiple Word Word8 where lgMul = wordLgMul +instance LgMultiple Word Word16 where lgMul = wordLgMul +instance LgMultiple Word Word32 where lgMul = wordLgMul +instance LgMultiple Word64 Word where lgMul = wordLgMul' + +wordLgMul :: forall a. (LgMultiple Word32 a, LgMultiple Word64 a) => LgMul Word a +wordLgMul = onWordConv (LgMul $ getLgMul (lgMul :: LgMul Word32 a)) (LgMul $ getLgMul (lgMul :: LgMul Word64 a)) + +wordLgMul' :: forall a. (LgMultiple a Word32, LgMultiple a Word64) => LgMul a Word +wordLgMul' = onWordConv (LgMul $ getLgMul (lgMul :: LgMul a Word32)) (LgMul $ getLgMul (lgMul :: LgMul a Word64)) + +instance Category LgMul where + id = LgMul 0 + LgMul a . LgMul b = LgMul $ a + b + +lgMulTrans :: forall a b c. (LgMultiple a b, LgMultiple b c) => Tagged b (LgMul a c) +lgMulTrans = tag $ lgMul . (at :: At b) idAt . lgMul + +idAt :: Category c => Tagged a (c a a) +idAt = tag id + +bitSizeLen :: forall a b. (Bits a, Integral b) => Tagged a (Len Bool b) +bitSizeLen = tag $ Len $ fromIntegral $ bitSize (undefined :: a) + +wordLenB :: WordConv a => Bijection' (Len Word b) (Len a b) +wordLenB = uncheckedBijection (Len . getLen) (Len . getLen) + +refineLen :: forall u v n. (Bits n, LgMultiple u v) => Len u n -> Len v n +refineLen (Len u) = Len $ u `shiftL` getLgMul (lgMul :: LgMul u v) +coarsenLen :: forall u v n. (Bits n, LgMultiple v u) => Len u n -> Len v n +coarsenLen (Len u) = Len $ ceilDivPower2 (getLgMul (lgMul :: LgMul v u)) u + +{-# INLINE coarseRem #-} +coarseRem :: forall u v n. (Bits n, LgMultiple v u) => Len u n -> (Len v n, Len u n) +coarseRem (Len u) = let s = getLgMul (lgMul :: LgMul v u) in (Len $ u `shiftR` s, Len $ u .&. ((1 `shiftL` s) - 1)) + +ceilDivPower2 n x = (x + ((1 `shiftL` n) - 1)) `shiftR` n +roundUpPower2 n x = ceilDivPower2 n x `shiftL` n + +instance Super a b => Super (Len u a) (Len u b) where super = injectionM' (inv struct) . super . injectionM' struct + +deriveStructured ''Len
+ src/Cgm/Data/List.hs view
@@ -0,0 +1,105 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++-----------------------------------------------------------------------------+--+-- Module : List+-- Copyright :+-- License : AllRightsReserved+--+-- Maintainer :+-- Stability :+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++{-# LANGUAGE FlexibleContexts, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, TypeFamilies, TupleSections #-}++module Cgm.Data.List (+ testList,+ List(..),+ listHead,+ addListContext,+ foldWithContext,+ prependReverse,+ listFoldMap,+ Sizable(..),+ listStructure,+ maybeMaximumBy,+ maxBy,+ unfoldlE,+ unfoldrE+) where++--import Data.Foldable+import Data.Collections.Foldable as Foldable+import Data.Monoid+import Cgm.Control.Combinators+import Cgm.Control.InFunctor+import Control.Arrow++testList :: b -> (a -> [a] -> b) -> [a] -> b+testList empty nonEmpty list = case list of {[] -> empty; (x:xs) -> nonEmpty x xs}++class List a where+ type Listed a :: *+ onList :: b -> (Listed a -> a -> b) -> a -> b+ consList :: Listed a -> a -> a+ emptyList :: a++prependReverse :: List a => a -> a -> a+prependReverse rev end = onList end (\r rs -> prependReverse rs $ consList r end) rev++instance List [a] where+ type Listed [a] = a+ onList e _ [] = e+ onList _ c (x:xs) = c x xs+ consList = (:)+ emptyList = []++listFoldMap :: (List a, Monoid m) => (Listed a -> m) -> a -> m+listFoldMap f = onList mempty $ dot2 mappend f $ listFoldMap f++listHead :: List a => a -> Maybe (Listed a)+listHead = onList Nothing (Just ./ const)++-- For each element in a List, it makes available a reversed List of elements that come before it, and a List of those that come after it.+addListContext :: (List a, List c, Listed a ~ Listed c) => a -> [(c, Listed a, a)]+addListContext = foldWithContext (\before elem after -> ((before, elem, after) :)) []++foldWithContext :: (List a, List c, Listed a ~ Listed c) => (c -> Listed a -> a -> b -> b) -> b -> a -> b+foldWithContext f e = fold2 emptyList+ where fold2 revPrefix = onList e (\x suffix -> f revPrefix x suffix (fold2 (consList x revPrefix) suffix))++-- counts the elements, returning Nothing if at least i elements were present, or i-length if less than i elements were present+class Sizable a where countDown :: Int -> a -> Maybe Int++listStructure :: List a => Bijection' a (Maybe (Listed a, a))+listStructure = uncheckedBijection (onList Nothing $ Just ./ (,)) (maybe emptyList $ uncurry consList)++maybeMaximumBy :: Foldable l a => (a -> a -> Ordering) -> l -> Maybe a+maybeMaximumBy o = Foldable.foldr (\a -> Just . maybe a (maxBy o a)) Nothing+ +maxBy :: (a -> a -> Ordering) -> a -> a -> a+maxBy o a b = case o a b of {GT -> a; _ -> b}++-- similar to unfoldl but uses Either instead of Maybe to signal the end of the list+unfoldlE :: (b -> Either c (b, a)) -> b -> (c, [a])+unfoldlE f = unfoldl' []+ where unfoldl' as = either (, as) (\(b', a) -> unfoldl' (a : as) b') . f++-- similar to unfoldr but uses Either instead of Maybe to signal the end of the list+unfoldrE :: (b -> Either c (a, b)) -> b -> ([a], c)+unfoldrE f = either ([], ) (\(a, b') -> first (a:) $ unfoldrE f b') . f
+ src/Cgm/Data/LongWord.hs view
@@ -0,0 +1,28 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TemplateHaskell, TypeFamilies #-} + +module Cgm.Data.LongWord ( + Word128, + word128BE + ) where + +import Cgm.Data.Word +import Cgm.Data.Structured + +data Word128 = Word128 {word128_64 :: {-# UNPACK #-} !Word64, word128_0 :: {-# UNPACK #-} !Word64} deriving (Eq, Ord, Show) + +word128BE = Word128 + +deriveStructured ''Word128
+ src/Cgm/Data/MapMultiset.hs view
@@ -0,0 +1,38 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TypeFamilies, TemplateHaskell, DeriveDataTypeable #-} + +module Cgm.Data.MapMultiset( + MapMultiset(mapMultisetMap) + ) where + +import Prelude() +import Cgm.Prelude +import Cgm.Data.Maybe +import Cgm.Data.Multiset +import Cgm.Data.Typeable + +import Data.Map(Map) +import qualified Data.Map as Map + +newtype MapMultiset a = MapMultiset {mapMultisetMap :: Map a Integer} deriving Typeable + +instance Multiset MapMultiset where + emptySet = MapMultiset Map.empty + insert e (MapMultiset a) = MapMultiset $ Map.insertWith' (+) e 1 a + delete e (MapMultiset a) = fmap (\c -> MapMultiset $ if c == 1 then Map.delete e a else Map.insert e (c - 1) a) $ Map.lookup e a + +instance Ord a => Monoid (MapMultiset a) where + mempty = MapMultiset Map.empty + mappend (MapMultiset a) (MapMultiset b) = MapMultiset $ Map.unionWith (+) a b
+ src/Cgm/Data/Maybe.hs view
@@ -0,0 +1,55 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++-----------------------------------------------------------------------------+--+-- Module : Maybe+-- Copyright :+-- License : AllRightsReserved+--+-- Maintainer :+-- Stability :+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Cgm.Data.Maybe (+ module Data.Maybe,+ ifJust,+ justIf,+ predJust,+ firstJust,+ maybeToEither+) where++import Data.Monoid+import Data.Maybe+import Cgm.Control.Combinators+import Cgm.Data.Bool++ifJust :: Bool -> a -> Maybe a+ifJust = bool (const Nothing) Just++justIf :: a -> Bool -> Maybe a+justIf = flip ifJust++predJust :: (a -> Bool) -> a -> Maybe a+predJust p a = p a `ifJust` a++firstJust :: Maybe a -> Maybe a -> Maybe a+firstJust = getFirst ./ dot2i mappend First++maybeToEither :: b -> Maybe a -> Either b a+maybeToEither b = maybe (Left b) Right
+ src/Cgm/Data/Monoid.hs view
@@ -0,0 +1,39 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Data.Monoid( + (◊), + ø, + inter, + foldInter, + module Data.Monoid + ) where + +import Data.Monoid +import Data.Foldable +import Data.List + +-- Right associativity helps with performance, on [] or on Data.Text.Lazy.Builder for example +infixr 9 ◊ -- rfc1345="&LZ" +(◊) :: Monoid a => a -> a -> a +(◊) = mappend + +-- Unicode (LATIN SMALL LETTER O WITH STROKE) rfc1345="&o/" +ø :: Monoid m => m +ø = mempty + +inter :: Monoid m => m -> m -> m -> m +inter i a b = a ◊ i ◊ b + +foldInter :: (Monoid m, Foldable l) => m -> l m -> m +foldInter i l = fold $ intersperse i $ toList l
+ src/Cgm/Data/Multiset.hs view
@@ -0,0 +1,34 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TypeFamilies, FlexibleContexts #-} + +module Cgm.Data.Multiset ( + Multiset(..) + ) where + +import Prelude() +import Cgm.Prelude +import Cgm.Data.Maybe + +class Multiset a where + emptySet :: a e + insert :: Ord e => e -> a e -> a e + delete :: Ord e => e -> a e -> Maybe (a e) -- ^ Returns Nothing when the elem was absent + +-- | Inefficient instance. May be useful as a temporary solution. +instance Multiset [] where + emptySet = [] + insert = (:) + delete e a = case break (== e) a of (before, rest) -> (before ++ tail rest) `justIf` not (null rest) +
+ src/Cgm/Data/NEList.hs view
@@ -0,0 +1,29 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Data.NEList ( + NEList, + neSingleton, + neCons, + onNEList, + neAppend + ) where + +-- Non empty list + +data NEList a = Single a | NECons a (NEList a) deriving Show +neSingleton = Single +neCons = NECons +onNEList :: (a -> Maybe (NEList a) -> z) -> NEList a -> z +onNEList f l = case l of {Single a -> f a Nothing; NECons a r -> f a (Just r)} +neAppend l1 l2 = onNEList (\a1 r1 -> neCons a1 $ maybe id neAppend r1 l2) l1
+ src/Cgm/Data/Nat.hs view
@@ -0,0 +1,35 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++-----------------------------------------------------------------------------+--+-- Module : Nat+-- Copyright :+-- License : AllRightsReserved+--+-- Maintainer :+-- Stability :+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------+++module Cgm.Data.Nat (+ module Cgm.Data.Nat.Base,+ module Cgm.Data.Nat.Constants+) where++import Cgm.Data.Nat.Base+import Cgm.Data.Nat.Constants
+ src/Cgm/Data/Nat/Base.hs view
@@ -0,0 +1,177 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, TypeFamilies, Rank2Types, FlexibleContexts, GADTs, TypeOperators, DeriveDataTypeable #-}++module Cgm.Data.Nat.Base (+ D0,+ d0,+ Nat(..),+ Succ,+ intOfNat,+ (:+:),+ addZ,+ addS,+ addSC,+ addC,+ addComm,+ (:-:),+ subZ,+ subS,+ subI,+ addSub,+ geTrans,+ module Cgm.Data.Tagged+) where++import Control.Applicative+import Cgm.Data.Tagged+import Data.Typeable++data D0 = D0 deriving Typeable+newtype Succ n = Succ n deriving Typeable++d0 = D0++-- Similar to http://www.mail-archive.com/haskell-cafe@haskell.org/msg60806.html++class Nat n where onNat :: (n ~ D0 => c) -> (forall n'. (Succ n' ~ n, Nat n') => Tagged n' c) -> Tagged n c+instance Nat D0 where onNat z _ = Tagged z+instance Nat n => Nat (Succ n) where onNat _ s = Tagged $ untag s++intOfNat :: Nat a => Tagged a Int+intOfNat = onNat 0 $ (+ 1) <$> intOfNat++on2Nats :: (Nat a, Nat b) => + ((a ~ D0, b ~ D0) => z) -> + (forall b'. (a ~ D0, Succ b' ~ b, Nat b') => Tagged b' z) -> + (forall a'. (Succ a' ~ a, Nat a', b ~ D0) => Tagged a' z) -> + (forall a' b'. (Succ a' ~ a, Nat a', Succ b' ~ b, Nat b') => Tagged2 a' b' z) -> + Tagged2 a b z+on2Nats zz zs sz ss = onNat (onNat zz zs) $ flipTags $ onNat sz $ flipTags ss++--instance Show (Nat a) where+-- showsPrec _ D0 = showString "d0"+-- showsPrec p a@(S n) = if (natToInt a <= 65)+-- then showString ("d" ++ show (natToInt a))+-- else showParen (p > 10) $ showString "S" . showChar ' ' . showsPrec 11 n++--++--type family Nest n (f :: * -> *) a+--type instance Nest D0 f a = a+--type instance Nest (Nat (Succ n)) f a = f (Nest n f a)++--nest :: Nat n -> (forall a. a -> f a) -> a -> Nest n f a+--nest D0 f a = a+--nest (S n) f a = f (nest n f a)++-- Add++type family a :+: b+type instance D0 :+: D0 = D0+type instance D0 :+: Succ b = Succ b+type instance Succ a :+: D0 = Succ a+type instance Succ a :+: Succ b = Succ (Succ (a :+: b))++addZ :: Nat b => (((D0 :+: b) ~ b, (b :+: D0) ~ b) => c) -> Tagged b c+addZ c = onNat c $ tag c++addS :: forall a b z. (Nat a, Nat b) => ((Succ a :+: b) ~ Succ (a :+: b) => z) -> Tagged2 a b z+addS z = on2Nats z (addZ z) (tag z) $ addS z+--This is what the above definition looked like before we used on2Nats:+--addS c = onNat (onNat c $ addZ c) (flipTags $ onNat (tag c) $ flipTags $ addS c)++addSC :: forall a b z. (Nat a, Nat b) => (((Succ a :+: b) ~ Succ (a :+: b), Nat (a :+: b)) => z) -> Tagged2 a b z+addSC z = on2Nats z (addZ z) (tag z) $ addSC z++addSR :: forall a b z. (Nat a, Nat b) => ((a :+: Succ b) ~ Succ (a :+: b) => z) -> Tagged2 a b z+addSR z = on2Nats z (tag z) (addZ z) $ addSR z++addComm :: forall a b z. (Nat a, Nat b) => ((a :+: b) ~ (b :+: a) => z) -> Tagged2 a b z+addComm z = on2Nats z (tag z) (tag z) $ addComm z++addC :: forall a b z. (Nat a, Nat b) => (Nat (a :+: b) => z) -> Tagged2 a b z+addC z = on2Nats z (tag z) (tag z) $ addC z++-- Subtract++-- We use only the canonical representation: Succ (Pred a) is never used, and neither is Pred (Succ a)+newtype Pred n = Pred n++type family a :-: b+type instance D0 :-: D0 = D0+type instance D0 :-: Succ a = Pred a+type instance Succ a :-: D0 = Succ a+type instance Succ a :-: Succ b = a :-: b++newtype Neg a = Neg a++-- Usatisfiable context, would prove any z+--zSubS :: forall a z. (Nat a, Nat (D0 :-: Succ a)) => (D0 ~ Succ D0 => z) -> Tagged a z+--zSubS z = (at :: At (D0 :-: Succ a)) $ onNat (onNat z (tag z)) (flipTags $ onNat (tag z) (flipTags $ zSubS z))++-- GHC produces an error on dead code, instead of not checking it. Not checking at all might be confusing+-- when the code was not expected by the programmer to be dead. So a warning seems appropriate (but there should be no type errors,+-- no matter what the code contains). When the programmer expects the code to be dead, it should be possible+-- to write dead code which does not produce the warning. One solution would be to warn only when the dead code+-- calls non-dead code (more precisely, code that the compiler cannot determine to be dead based on its incomplete checks.)+-- This way a special function dead :: Bool ~ Int => a could be called to disable the warning, but recursive calls to the dead-code would+-- also not generate any warning. Using undefined instead of dead would no be satisfactory, since undefined may be used+-- anywhere including in non-dead code, without producing any error.+-- As a temporary solution, we define badNat :: Nat (Pred D0) => z, which is similar to undefined, but requires a proof+-- that we are in quasi-dead code, code which violates the invariants on Nat, and which may legally call an intOfNat which+-- is undefined. If we had the treatment discussed above for dead-code, we could replace uses of this by onNat dead dead+badNat :: Nat (Pred a) => Tagged (Pred a) z+badNat = undefined -- equavalient to (intOfNat `seq` undefined)++subZ :: Nat b => ((b :-: D0) ~ b => z) -> Tagged b z+subZ z = onNat z $ Tagged z++subI :: Nat b => ((b :-: b) ~ D0 => z) -> Tagged b z+subI z = onNat z $ subI z++subS :: forall a b z. (Nat a, Nat b, Nat (a :-: b)) => ((Succ a :-: b) ~ Succ (a :-: b) => z) -> Tagged2 a b z+subS z = on2Nats z (tag $ (at :: At (a :-: b)) badNat) (tag z) $ subS z++addSubI :: forall a b z. (Nat a, Nat b) => (((a :+: b) :-: b) ~ a => z) -> Tagged2 a b z+addSubI z = on2Nats z (dupTag $ addZ $ (at :: At D0) $ addSubI z)+ (tag z) $ dup2Tags $ addS $ tag $ (at :: At a) $ addSubI z++addSub :: forall a b c z. (Nat a, Nat b, Nat c, Nat (b :-: c)) => ((((a :+: b) :-: c) ~ (a :+: (b :-: c)), Nat (a :+: (b :-: c))) => z) -> Tagged3 a b c z+addSub z = onNat ((at2 :: At2 b (b :-: c)) $ addZ $ addZ $ tag2 z) addSubS where+ addSubS :: forall a'. (Nat a', a ~ Succ a') => Tagged3 a' b c z+ addSubS = addSub $ + (at2 :: At2 a' (b :-: c)) $ addSC $+ (at2 :: At2 a' b) $ addSC $+ (at2 :: At2 (a' :+: b) c) $ subS z++--subRS :: forall a b z. (Nat a, Nat (b :-: Succ a)) => (Succ (b :-: Succ a) ~ (b :-: a) => z) -> Tagged2 a b z++geTrans :: forall a b c z. (Nat a, Nat b, Nat c, Nat (a :-: b), Nat (b :-: c)) => (Nat (a :-: c) => z) -> Tagged3 a b c z+geTrans = undefined++++-- Notes+-- We have no true kind system, so polymorphic data types may be instantiated at any type, whether it makes sense or not.+-- However we can express the constraint on types as type equality constraints and/or type classes, to be attached+-- to all methods involving the type.+-- These constrains rely on type classes and type families, which are always open. We can close them with+-- the NatArg/IsNat trick below, but this just closes them to a single type constructor, in which case+-- the type family could have been defined on the argument of the constructor.+--type family NatArg a+--type instance NatArg (Nat a) = a+--class Nat (NatArg a) ~ a => IsNat a+--instance IsNat (Nat a)+
+ src/Cgm/Data/Nat/Constants.hs view
@@ -0,0 +1,86 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++module Cgm.Data.Nat.Constants where++import Cgm.Data.Nat.Base++-- putStr $ unlines $ ["type D" ++ show x ++ " = Succ D" ++ show (x-1) | x <- [1..65]]+type D1 = Succ D0+type D2 = Succ D1+type D3 = Succ D2+type D4 = Succ D3+type D5 = Succ D4+type D6 = Succ D5+type D7 = Succ D6+type D8 = Succ D7+type D9 = Succ D8+type D10 = Succ D9+type D11 = Succ D10+type D12 = Succ D11+type D13 = Succ D12+type D14 = Succ D13+type D15 = Succ D14+type D16 = Succ D15+type D17 = Succ D16+type D18 = Succ D17+type D19 = Succ D18+type D20 = Succ D19+type D21 = Succ D20+type D22 = Succ D21+type D23 = Succ D22+type D24 = Succ D23+type D25 = Succ D24+type D26 = Succ D25+type D27 = Succ D26+type D28 = Succ D27+type D29 = Succ D28+type D30 = Succ D29+type D31 = Succ D30+type D32 = Succ D31+type D33 = Succ D32+type D34 = Succ D33+type D35 = Succ D34+type D36 = Succ D35+type D37 = Succ D36+type D38 = Succ D37+type D39 = Succ D38+type D40 = Succ D39+type D41 = Succ D40+type D42 = Succ D41+type D43 = Succ D42+type D44 = Succ D43+type D45 = Succ D44+type D46 = Succ D45+type D47 = Succ D46+type D48 = Succ D47+type D49 = Succ D48+type D50 = Succ D49+type D51 = Succ D50+type D52 = Succ D51+type D53 = Succ D52+type D54 = Succ D53+type D55 = Succ D54+type D56 = Succ D55+type D57 = Succ D56+type D58 = Succ D57+type D59 = Succ D58+type D60 = Succ D59+type D61 = Succ D60+type D62 = Succ D61+type D63 = Succ D62+type D64 = Succ D63+type D65 = Succ D64+++-- putStr $ unlines $ ["d" ++ show x ++ " = S d" ++ show (x-1) | x <- [1..65]]
+ src/Cgm/Data/SortedPair.hs view
@@ -0,0 +1,34 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Data.SortedPair ( + SortedPair, + onSortedPair, + sortedPair, + unsafeSortedPair + ) where + +import Cgm.Control.InFunctor + +-- SortedPair +-- The two values cannot be equal. The second is strictly greater than the first. + +data SortedPair a = SortedPair a a deriving Show +onSortedPair :: (a -> a -> z) -> SortedPair a -> z +onSortedPair f (SortedPair a1 a2) = f a1 a2 +sortedPair :: Ord a => a -> a -> SortedPair a +sortedPair a1 a2 = if a1 <= a2 then SortedPair a1 a2 else SortedPair a2 a1 +unsafeSortedPair = SortedPair + +instance StrictlyIncreasingFunctor SortedPair where sincmap f (SortedPair a1 a2) = SortedPair (f $* a1) (f $* a2) +
+ src/Cgm/Data/Structured.hs view
@@ -0,0 +1,79 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE TypeFamilies, TemplateHaskell #-}++module Cgm.Data.Structured (+ Structured(..),+ struct,+ wrap,+ unwrap,+ in1,+ in2,+ structureMap,+ deriveStructured,+ module Cgm.Control.InFunctor+) where++import Cgm.Data.Structured.Derive++import Control.Arrow+import Data.Functor.Compose+import Cgm.Control.Combinators+import Cgm.Control.InFunctor++-- Similar to instant-generics but we reuse the haskell types (), (,) and Either+-- We do not make construtors explicit, nor de we introduce types Var and Rec++class Structured a where+ type Structure a+ structure :: a -> Structure a+ fromStructure :: Structure a -> a++deriveStructured ''(,,)+deriveStructured ''(,,,)+deriveStructured ''(,,,,)+deriveStructured ''(,,,,,)+deriveStructured ''[]+deriveStructured ''Maybe+deriveStructured ''Bool+deriveStructured ''Ordering++deriveStructured ''Kleisli+deriveStructured ''Compose+deriveStructured ''RevFun++{-# INLINE struct #-}+struct :: Structured a => Bijection' a (Structure a)+struct = uncheckedBijection structure fromStructure++-- TODO: decide if we replace structure and fromStructure with those+{-# INLINE unwrap #-}+unwrap :: Structured a => a -> Structure a+unwrap = structure+{-# INLINE wrap #-}+wrap :: Structured a => Structure a -> a+wrap = fromStructure++{-# INLINE in1 #-}+in1 :: (Structured a, Structured b) => (Structure a -> Structure b) -> a -> b+in1 f = wrap . f . unwrap++{-# INLINE in2 #-}+in2 :: (Structured a, Structured b, Structured c) => (Structure a -> Structure b -> Structure c) -> a -> b -> c+in2 f = wrap ./ dot2 f unwrap unwrap++{-# INLINE structureMap #-}+structureMap :: (InjectionACofunctor p, Structured a) => p (Structure a) -> p a+structureMap = (`iacomap` struct)+
+ src/Cgm/Data/Structured/Derive.hs view
@@ -0,0 +1,176 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}+++module Cgm.Data.Structured.Derive (+ deriveStructured+) where++import Language.Haskell.TH+import Control.Monad++-- TODO: Deriving an instance is problematic since it must be exported. And most often this is+-- undesirable because it breaks the type abstraction. Instead we should derive+-- a method which provides the bijection, and modules which perform the derivation +-- would then be free to define an instance and/or use the bijection. We may want to+-- derive a structure type also.++--instance Structured a => Structured [a] where+-- type Structure [a] = Either () (a, [a])+-- structure [] = Left ()+-- structure (x : xs) = Right (x, xs)+-- fromStructure (Left ()) = []+-- fromStructure (Right (x, xs)) = (x : xs)++--[InstanceD [ClassP Structured.Structured [VarT a_0]]+-- (AppT (ConT Structured.Structured)+-- (AppT ListT (VarT a_0)))+-- [TySynInstD Structure+-- [AppT ListT (VarT a_1)]+-- (AppT (AppT (ConT Data.Either.Either) (ConT GHC.Unit.()))+-- (AppT (AppT (TupleT 2) (VarT a_1))+-- (AppT ListT (VarT a_1)))),+-- FunD structure [Clause [ConP GHC.Types.[] []]+-- (NormalB (AppE (ConE Data.Either.Left) (ConE GHC.Unit.()))) [],+-- Clause [InfixP (VarP x_2) GHC.Types.: (VarP xs_3)]+-- (NormalB (AppE (ConE Data.Either.Right) (TupE [VarE x_2,VarE xs_3]))) []],+-- FunD fromStructure [Clause [ConP Data.Either.Left [ConP GHC.Unit.() []]]+-- (NormalB (ConE GHC.Types.[])) [],+-- Clause [ConP Data.Either.Right [TupP [VarP x_4,VarP xs_5]]]+-- (NormalB (InfixE (Just (VarE x_4)) (ConE GHC.Types.:) (Just (VarE xs_5)))) []]]]++-- Options for defintion of generic persistence++-- http://www.cse.unsw.edu.au/~chak/papers/instant-generics.pdf is interresting but its+-- implementation instant-generics, does not yet come with a Template Haskell+-- function to derive Representable instances++-- See also "A generic deriving mechanism for Haskell, Draft"+-- (http://www.dreixel.net/research/pdf/gdmh_draft.pdf)+-- To be presented at Haskell Symposium 2010, in September+-- Implementation is in UHC, not GHC for now.++-- GDMH seems very powerful, but it appears we do not need tagging and meta-information.+-- It also avoids using type families and functional dependencies, to show that their+-- design is workable without those new features. But here we can use type famillies+-- as in instant-generics. We could use the instant-generics design (and library).+-- We might not need to use the shallow representation, but if we stay close to+-- their design we will have less thinking to do, and we may be able to use+-- their library directly (and add TH to derive instances). The shallow representation appears+-- necessary to support subuniverses for specific generic methods (something we think+-- we do no need at this point).++-- DEBUG with -ddump-splices++deriveStructured :: Name -> Q [Dec]+deriveStructured typName =+ do (TyConI d) <- reify typName+ (type_name,tvars,_,constructors) <- typeInfo (return d)+ appliedType <- appsT $ conT' type_name : map (varT . fromTyVar) tvars+ let structureType = tySynInstD (mkName "Structure") [return appliedType] $+ nestedEitherT $ map (nestedTupT . map (return . snd) . snd) constructors+ structureFun = do clauses <- mapM structureClause constructors+ return $ FunD (mkName "structure") $ addETags clauses+ structureClause (conName, components) =+ do vars <- newNames "a" components+ clause [conP conName $ map varP vars] (normalB $ nestedTupE $ map varE vars) []+ fromStructureFun =+ do clauses <- mapM fromStructureClause constructors+ return $ FunD (mkName "fromStructure") $ addPTags clauses+ fromStructureClause (conName, components) =+ do vars <- newNames "s" components+ clause [nestedTupP $ map varP vars] (normalB (appsE (conE conName : map varE vars))) []+ in sequence [instanceD (cxt []) (appT (conT $ mkName "Structured") (return appliedType))+ [structureType, structureFun, fromStructureFun]]++conT' name = if nameBase name == "[]" then listT else conT name++-- A foldr with special cases for empty lists and singletons+nested :: b -> (a -> b) -> (a -> b -> b) -> [a] -> b+nested empty single pair [] = empty+nested empty single pair (x:[]) = single x+nested empty single pair (x:xs) = pair x $ nested empty single pair xs++nestedTupE = nested (tupE []) id (\a b -> tupE [a, b])+nestedTupT = nested (tupT []) id (\a b -> tupT [a, b])+nestedTupP = nested (tupP []) id (\a b -> tupP [a, b])+nestedEitherT = nested (error "nestedEitherT []") id eitherT++addETags = nested [] return $ \c cs -> mapClauseBodyE leftETag c : map (mapClauseBodyE rightETag) cs+addPTags = nested [] return $ \c cs -> mapClausePat1 leftPTag c : map (mapClausePat1 rightPTag) cs+leftETag = AppE $ ConE $ mkName "Left"+rightETag = AppE $ ConE $ mkName "Right"+leftPTag p = ConP (mkName "Left") [p]+rightPTag p = ConP (mkName "Right") [p]+mapClauseBodyE f (Clause ps b ds) = Clause ps (mapBodyE f b) ds+mapClausePat1 f (Clause [p] b ds) = Clause [f p] b ds+mapBodyE f (GuardedB gs) = GuardedB $ map (\p -> (fst p, f $ snd p)) gs+mapBodyE f (NormalB e) = NormalB $ f e++appsT :: [TypeQ] -> TypeQ+appsT [] = error "appsT []"+appsT [x] = x+appsT (x:y:zs) = appsT $ appT x y : zs++tupT ts = appsT $ tupleT (length ts) : ts++eitherT ta tb = appsT [conT (mkName "Either"), ta, tb]++fromTyVar :: TyVarBndr -> Name+fromTyVar (PlainTV v) = v+fromTyVar (KindedTV v _) = v++newNames prefix = mapM $ const $ newName prefix++-- And some borrowed helper code taken from Syb III / replib 0.2++typeInfo :: DecQ -> Q (Name, [TyVarBndr], [(Name, Int)], [(Name, [(Maybe Name, Type)])])+typeInfo m =+ do d <- m+ case d of+ d@DataD{} ->+ return (simpleName $ name d, paramsA d, consA d, termsA d)+ d@NewtypeD{} ->+ return (simpleName $ name d, paramsA d, consA d, termsA d)+ _ -> error ("derive: not a data type declaration: " ++ show d)++ where+ consA (DataD _ _ _ cs _) = map conA cs+ consA (NewtypeD _ _ _ c _) = [ conA c ]++ paramsA (DataD _ _ ps _ _) = ps+ paramsA (NewtypeD _ _ ps _ _) = ps++ termsA (DataD _ _ _ cs _) = map termA cs+ termsA (NewtypeD _ _ _ c _) = [ termA c ]++ termA (NormalC c xs) = (c, map (\x -> (Nothing, snd x)) xs)+ termA (RecC c xs) = (c, map (\(n, _, t) -> (Just $ simpleName n, t)) xs)+ termA (InfixC t1 c t2) = (c, [(Nothing, snd t1), (Nothing, snd t2)])++ conA (NormalC c xs) = (simpleName c, length xs)+ conA (RecC c xs) = (simpleName c, length xs)+ conA (InfixC _ c _) = (simpleName c, 2)++ name (DataD _ n _ _ _) = n+ name (NewtypeD _ n _ _ _) = n+ name d = error $ show d++simpleName :: Name -> Name+simpleName nm =+ let s = nameBase nm+ in case dropWhile (/=':') s of+ [] -> mkName s+ _:[] -> mkName s+ _:t -> mkName t+
+ src/Cgm/Data/Super.hs view
@@ -0,0 +1,69 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE MultiParamTypeClasses, ScopedTypeVariables, TypeOperators #-}++module Cgm.Data.Super (+ Super(..),+ up,+ superSInc,+ narrowIntegral,+ module Cgm.Data.Maybe,+ module Cgm.Control.InFunctor+) where++import Data.Int+import Data.Word+import Data.Bits+import Control.Applicative+import Cgm.Data.Maybe+import Cgm.Control.InFunctor++-- Laws: properties of and relations on between values in a must still hold in b. For example 0 must map to 0, and Ord must be respected.+-- However some properites cannot hold, such as (== maxBound). So this law needs some elaboration.+class Super a b where+ super :: InjectionM' a b++superSInc :: Super a b => a :>> b+superSInc = uncheckedStrictlyIncreasing (apply super)++up :: Super a b => a -> b+up = apply super++instance Super Word8 Word64 where super = integralInjectionMaxOnly+instance Super Word8 Word32 where super = integralInjectionMaxOnly+instance Super Word8 Word16 where super = integralInjectionMaxOnly+instance Super Word16 Word64 where super = integralInjectionMaxOnly+instance Super Word16 Word32 where super = integralInjectionMaxOnly+instance Super Word32 Word64 where super = integralInjectionMaxOnly++instance Super Word8 Word where super = integralInjectionMaxOnly+instance Super Word16 Word where super = integralInjectionMaxOnly+instance Super Word32 Word where super = integralInjectionMaxOnly+instance Super Word Word64 where super = integralInjectionMaxOnly++instance Super Word8 Integer where super = integralInjection ++integralInjectionMaxOnly :: forall a b. (Integral a, Integral b, Bounded a) => InjectionM' a b+integralInjectionMaxOnly = uncheckedInjectionM fromIntegral narrowIntegralMaxOnly++integralInjection :: forall a b. (Integral a, Integral b, Bounded a) => InjectionM' a b+integralInjection = uncheckedInjectionM fromIntegral narrowIntegral++{-# INLINE narrowIntegral #-}+narrowIntegral :: forall a b. (Integral a, Integral b, Bounded b) => a -> Maybe b+narrowIntegral = (fromIntegral <$>) . predJust (\a -> fromIntegral (minBound :: b) <= a && a <= fromIntegral (maxBound :: b))++narrowIntegralMaxOnly :: forall a b. (Integral a, Integral b, Bounded b) => a -> Maybe b+narrowIntegralMaxOnly = (fromIntegral <$>) . predJust (<= fromIntegral (maxBound :: b))+
+ src/Cgm/Data/Tagged.hs view
@@ -0,0 +1,96 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}+++{-# LANGUAGE Rank2Types #-}++module Cgm.Data.Tagged (+ module Data.Tagged,+ tag,+ at,+ At,+ Tagged2,+ tag2,+ at2,+ At2,+ Tagged3,+ tag3,+ at3,+ At3,+ Tagged4,+ tag4,+ at4,+ At4,+ flipTags,+ rot3Tags,+ rot3Tags2,+ rot4Tags,+ rot4Tags2,+ rot4Tags3,+ dupTag,+ dup2Tags,+ pushTagIn,+ constAt+) where++import Data.Tagged+import Control.Applicative+import Cgm.Control.Combinators++type At a = forall z. Tagged a z -> z+at = untag++type Tag a = forall z. z -> Tagged a z+tag = Tagged++type Tagged2 a b z = Tagged a (Tagged b z)+tag2 = tag . tag+type At2 a b = forall z. Tagged2 a b z -> z+at2 = at . at++type Tagged3 a b c z = Tagged a (Tagged2 b c z)+tag3 = tag . tag2+type At3 a b c = forall z. Tagged3 a b c z -> z+at3 = at . at . at++type Tagged4 a b c d z = Tagged a (Tagged3 b c d z)+tag4 = tag . tag3+type At4 a b c d = forall z. Tagged4 a b c d z -> z+at4 = at . at . at . at++flipTags :: Tagged2 a b z -> Tagged2 b a z+flipTags = tag2 . at2++rot3Tags :: Tagged3 b c a z -> Tagged3 a b c z+rot3Tags = tag3 . at3+rot3Tags2 :: Tagged3 c a b z -> Tagged3 a b c z+rot3Tags2 = tag3 . at3++rot4Tags :: Tagged4 b c d a z -> Tagged4 a b c d z+rot4Tags = tag4 . at4+rot4Tags2 :: Tagged4 c d a b z -> Tagged4 a b c d z+rot4Tags2 = tag4 . at4+rot4Tags3 :: Tagged4 d a b c z -> Tagged4 a b c d z+rot4Tags3 = tag4 . at4++dupTag :: Tagged2 a a z -> Tagged a z+dupTag = tag . at2++dup2Tags :: Tagged4 a b a b z -> Tagged2 a b z+dup2Tags = tag2 . at4++pushTagIn :: Functor f => Tagged a (f b) -> f (Tagged a b)+pushTagIn = (tag <$>) . untag++constAt :: Tagged b a -> b -> a+constAt = at ./ const
+ src/Cgm/Data/Typeable.hs view
@@ -0,0 +1,19 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Data.Typeable( + module Data.Typeable + ) where + +import Data.Typeable +
+ src/Cgm/Data/Word.hs view
@@ -0,0 +1,121 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE MagicHash, TypeFamilies, Rank2Types, MultiParamTypeClasses, FunctionalDependencies, FlexibleContexts #-} + +module Cgm.Data.Word ( + WordConv(..), + onWordConv, + onWordConvB, + wordBits, + partialShiftL, + partialShiftRL, + uShiftL, + uShiftRL, + unI#, + unW#, + Signed(..), + unsigned, + WordConv1(..), + splitWord64LE, + module Data.Word + ) where + +import Prelude() +import Cgm.Prelude +import Control.Category +import Data.Bits +import Data.Int +import Data.Word +import GHC.Prim +import GHC.Exts +import Cgm.Control.InFunctor +import Cgm.Data.Tagged +import Cgm.Data.WordN +import Cgm.Control.Combinators + +{-# INLINE wordBits #-} +wordBits :: Integral a => a +wordBits = fromIntegral $ bitSize (undefined :: Word) + + +class WordConv a where + wordConv :: Bijection' Word a + +onWordConvB :: (Bijection' Word Word32 -> z) -> (Bijection' Word Word64 -> z) -> z +onWordConvB a b = onWordConv (a wordConv) (b wordConv) + +onWordConv :: (WordConv Word32 => z) -> (WordConv Word64 => z) -> z + +#if WORDSIZE == 32 +instance WordConv Word32 where + wordConv = uncheckedBijection fromIntegral fromIntegral +onWordConv a _ = a +#endif + +#if WORDSIZE == 64 +instance WordConv Word64 where + wordConv = uncheckedBijection fromIntegral fromIntegral +onWordConv _ a = a +#endif + +-- | 0 <= n < wordBits +{-# INLINE partialShiftL #-} +partialShiftL :: Word -> Word -> Word +partialShiftL (W# w) (W# n) = W# (w `uncheckedShiftL#` word2Int# n) + +-- | 0 <= n < wordBits +{-# INLINE partialShiftRL #-} +partialShiftRL :: Word -> Word -> Word +partialShiftRL (W# w) (W# n) = W# (w `uncheckedShiftRL#` word2Int# n) + +{-# INLINE uShiftL #-} +uShiftL :: Word -> Word -> Word +uShiftL w n = if n >= wordBits then 0 else partialShiftL w n + +{-# INLINE uShiftRL #-} +uShiftRL :: Word -> Word -> Word +uShiftRL w n = if n >= wordBits then 0 else partialShiftRL w n + +{-# INLINE unW# #-} +unW# (W# a) = a +{-# INLINE unI# #-} +unI# (I# a) = a + + +class Signed u s | u -> s, s -> u where signed :: Bijection' u s +instance Signed Word8 Int8 where + {-# INLINE signed #-} + signed = uncheckedBijection fromIntegral fromIntegral +instance Signed Word16 Int16 where + {-# INLINE signed #-} + signed = uncheckedBijection fromIntegral fromIntegral +instance Signed Word32 Int32 where + {-# INLINE signed #-} + signed = uncheckedBijection fromIntegral fromIntegral +instance Signed Word64 Int64 where + {-# INLINE signed #-} + signed = uncheckedBijection fromIntegral fromIntegral +instance Signed Word Int where + {-# INLINE signed #-} + signed = uncheckedBijection fromIntegral fromIntegral + +{-# INLINE unsigned #-} +unsigned :: Signed u s => Bijection' s u +unsigned = inv signed + +class WordConv1 a where + wordConv1 :: WordConv c => Bijection' (a Word) (a c) + +splitWord64LE :: Bijection' Word64 (Word32, Word32) +splitWord64LE = uncheckedBijection (fk (,) fromIntegral $ fromIntegral . (`shiftR` 32)) (\(l, h) -> fromIntegral h `shiftL` 32 + fromIntegral l)
+ src/Cgm/Data/WordN.hs view
@@ -0,0 +1,234 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE FlexibleInstances, +FlexibleContexts, +UndecidableInstances,+ScopedTypeVariables,+TypeSynonymInstances,+TypeOperators,+MultiParamTypeClasses, +TypeFamilies, +FunctionalDependencies, DeriveDataTypeable #-}++module Cgm.Data.WordN (+ RWord,+ toRWord,+ fromRWord,+ rWord,+ WordN(..),+ wordNBits,+ boolAsWord,+ RWordC,+ RWord8,+ RWord16,+ RWord32,+ RWord64,+ rChangeWord,+ rChangeWord',+ rAdd,+ rWordJoin,+ rWordSplit,+ rWordBool,+ module Cgm.Data.Nat,+ module Cgm.Data.Super+) where++import Data.Word+import Data.Int+import Data.Bits+import Control.Applicative+import GHC.Enum+import Cgm.Data.Bool+import Cgm.Data.Super+import Cgm.Data.Nat+import Cgm.Control.Combinators+import Cgm.Control.InFunctor+import Test.QuickCheck (Arbitrary(..), Gen)+import Data.Typeable++--testAddZ :: forall a. Nat a -> RWord (Add D0 (Nat a)) -> RWord (Nat a)+--testAddZ a r = addZ a r'+-- where r' :: (Add D0 (Nat a) ~ (Nat a)) => RWord (Nat a)+-- r' = r+--+--testRWordJoin :: forall a b. (NatClass a, NatClass b) => RWord (Nat a) -> RWord (Nat b) -> RWord (Add (Nat a) (Nat b))+--testRWordJoin a b = addComm (nat :: Nat a) (nat :: Nat b) $ addClosed (nat :: Nat b) (nat :: Nat a) $ \s -> rWordAdd (rWordJoin a b) $ rWordJoin b a+--+--runTestRWordJoin = print $ testRWordJoin (RWord 2 :: RWord D4) (RWord 3 :: RWord D5)++-- WordN++class (Bits w, Integral w, Nat (WordNBits w)) => WordN w where+ type WordNBits w :: *++instance WordN Word8 where type WordNBits Word8 = D8+instance WordN Word16 where type WordNBits Word16 = D16+instance WordN Word32 where type WordNBits Word32 = D32+instance WordN Word64 where type WordNBits Word64 = D64++wordNBits :: forall w. WordN w => w -> Int+wordNBits _ = (at :: At (WordNBits w)) intOfNat++-- RWord++newtype RWord w n = RWord {unRWord :: w} deriving Typeable++toRWord :: WordN w => w -> RWord w (WordNBits w)+toRWord = RWord++fromRWord :: RWord w n -> w+fromRWord = unRWord++rWord :: WordN w => Bijection' w (RWord w (WordNBits w))+rWord = uncheckedBijection toRWord fromRWord++boolAsWord :: Bijection' Bool (RWord Word8 D1)+boolAsWord = uncheckedBijection (bool 0 1) (== 1)++-- RWordC is just shorthand for an otherwise verbose context+class (WordN w, Nat n, Nat (WordNBits w :-: n)) => RWordC w n+instance (WordN w, Nat n, Nat (WordNBits w :-: n)) => RWordC w n++rWordJoin :: forall n m w. (Nat n, Nat m, Bits w) => RWord w n -> RWord w m -> Tagged n (RWord w (m :+: n))+rWordJoin (RWord un) (RWord um) = Tagged $ RWord $ um .|. (un `shiftL` (at :: At m) intOfNat)++rWordBool :: RWordC w D1 => RWord w D1 -> Bool+rWordBool = (`testBit` 0)++rWordSplit :: forall w n m. (RWordC w (n :+: m), RWordC w n, RWordC w m) => RWord w (n :+: m) -> Tagged m (RWord w m, RWord w n)+rWordSplit (RWord w) = Tagged $ (RWord (w `shiftR` (at :: At m) intOfNat), rClean $ RWord w)++rClean :: forall w n. RWordC w n => RWord w n -> RWord w n+rClean = liftRToR $ (.&.) $ (at :: At n) $ lowMaskNat++rSaturate :: forall w n. RWordC w n => RWord w n -> RWord w n+rSaturate = liftRToR $ (.|.) $ complement $ (at :: At n) $ lowMaskNat++-- TODO: The Nat ((WordNBits w) :-: n) is not used, so if it were defined as 'undefined' it would side-step out type checks (Nat only+-- closed if we exclude 'undefined' definitions). We could change the code so that it is used just to make sure it is not undefined.+-- Would representing the bound by a TBool valued type function be safer?+lowMaskNat :: RWordC w n => Tagged n w+lowMaskNat = (complement . shiftL (complement 0)) <$> intOfNat++-- TODO replace with more general versions in InFunctor, lift.... Oops no. That would no work. A Bijection cannot+-- be polymorphic. If we use a type function, like Structure, we could have more general lift functions.+liftRToA f = f . unRWord+liftAToR f = RWord . f+liftRToR f = RWord . f . unRWord+liftRRToR f = RWord ./ dot2i f unRWord -- could be written "wrapB rw rw rw", and we might then want to inline manually+liftRRToA f = dot2i f unRWord+liftRAToR f = RWord ./ dot2 f unRWord id+liftRRToRR f = (\(a, b) -> (RWord a, RWord b)) ./ dot2i f unRWord++-- Todo: remove Nat (WordNBits w' :-: n) which is redundant, it can be infered by transitivity: WordNBits w' >= n' >= n+--instance (RWordC w n, RWordC w' n', Nat (n' :-: n), Nat (WordNBits w' :-: n)) => Super (RWord w n) (RWord w' n') where +-- super = rMoreBits `composeM` rChangeWord+--instance RWordC w n => Super (RWord w n) w where+-- super = uncheckedBijection unRWord RWord `composeM` (rMoreBits :: InjectionM' (RWord w n) (RWord w (WordNBits w)))+-- The above two commented instances are subsumed by the following instance, which might be less efficient++instance (RWordC w n, RWordC w' n) => Super (RWord w n) w' where+ super = uncheckedInjectionM fromIntegral (((RWord . fromIntegral) <$>) . predJust (<= bound)) where+ bound = fromIntegral (maxBound :: RWord w n) :: w'++rChangeWord :: forall w w' n . (RWordC w n, RWordC w' n) => Bijection' (RWord w n) (RWord w' n)+rChangeWord = uncheckedBijection (RWord . fromIntegral . unRWord) (RWord . fromIntegral . unRWord)++rChangeWord' :: forall w w' n . (RWordC w n, WordN w', Nat (WordNBits w' :-: WordNBits w)) => Bijection' (RWord w n) (RWord w' n)+rChangeWord' = uncheckedBijection (RWord . fromIntegral . unRWord) (RWord . fromIntegral . unRWord)++rMoreBits :: forall w n n' d . (RWordC w n, Nat d, (n' :-: n) ~ d) => InjectionM' (RWord w n) (RWord w n')+rMoreBits = uncheckedInjectionM (liftRToR id) ((RWord <$>) . predJust (<= (at :: At n) lowMaskNat) . unRWord)++rAdd :: Num w => RWord w n -> RWord w n -> RWord w (Succ n)+rAdd = liftRRToR (+)++instance RWordC w n => Bounded (RWord w n) where+ minBound = 0+ maxBound = (at :: At n) $ dupTag $ subI $ lowMaskNat++instance RWordC w n => Bits (RWord w n) where+ (.&.) = liftRRToR (.&.)+ (.|.) = liftRRToR (.|.)+ xor = liftRRToR xor+ complement = liftRToR (`xor` (at :: At n) lowMaskNat)+ shiftL = rClean ./ liftRAToR shiftL+ shiftR = liftRAToR shiftR+ rotateL x i = shiftL x i .|. shiftR x ((at :: At n) intOfNat - i)+ rotateR x i = rotateL x ((at :: At n) intOfNat - i)+ bitSize _ = (at :: At n) intOfNat+ isSigned _ = False++instance RWordC w n => Ord (RWord w n) where+ compare = liftRRToA compare++instance RWordC w n => Enum (RWord w n) where+ succ = rClean . liftRToR succ . rSaturate+ pred = liftRToR pred+ toEnum = rClean . liftAToR toEnum . ((+) $ fromIntegral $ complement $ ((at :: At n) lowMaskNat :: w))+ fromEnum = liftRToA fromEnum+ enumFrom = boundedEnumFrom+ enumFromThen = boundedEnumFromThen++instance RWordC w n => Real (RWord w n) where+ toRational = liftRToA toRational++instance RWordC w n => Integral (RWord w n) where+ quot = liftRRToR quot+ rem = liftRRToR rem+ div = liftRRToR div+ mod = liftRRToR mod+ quotRem = liftRRToRR quotRem+ divMod = liftRRToRR divMod+ toInteger = liftRToA toInteger++instance RWordC w n => WordN (RWord w n) where+ type WordNBits (RWord w n) = n++instance RWordC w n => Eq (RWord w n) where+ (==) = liftRRToA (==)++instance (Show w, RWordC w n) => Show (RWord w n) where+ show = liftRToA show++instance RWordC w n => Num (RWord w n) where+ (+) = rClean ./ liftRRToR (+)+ (-) = rClean ./ liftRRToR (-)+ (*) = rClean ./ liftRRToR (*)+ negate = rClean . liftRToR negate+ fromInteger = rClean . liftAToR fromInteger+ abs = liftRToR abs+ signum = liftRToR signum++instance (Arbitrary w, RWordC w n) => Arbitrary (RWord w n) where+ arbitrary = (rClean . RWord) <$> arbitrary+ shrink = (RWord <$>) . shrink . unRWord++type RWord8 = RWord Word8+type RWord16 = RWord Word16+type RWord32 = RWord Word32+type RWord64 = RWord Word64++--type RangeT n iMin eMax = (n :>=: iMin) :&&: (n :<: eMax)+--+--type RWord n = If (RangeT n D0 D8) (RWord Word8 n)+-- (If (n :==: D8) Word8+-- (If (RangeT n D9 D16) (RWord Word16 n)+-- (If (n :==: D16) Word16+-- (If (RangeT n D17 D32) (RWord Word32 n)+-- (If (n :==: D32) Word32+-- (If (RangeT n D33 D64) (RWord Word64 n)+-- (If (n :==: D64) Word64+-- ())))))))+
+ src/Cgm/Prelude.hs view
@@ -0,0 +1,70 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +module Cgm.Prelude ( + counting, + --module Prelude.Plus, + module Control.Applicative, + module Control.Arrow, + module Control.Monad, + module Control.Exception, + module Control.Category, + module Data.Traversable, + module Data.Foldable, + module Data.Monoid, + module Data.List, + module Data.Function, + module Data.Ord, + module Prelude, + + module Cgm.Control.Combinators, + module Cgm.Control.InFunctor, + module Cgm.Data.Tagged, + module Cgm.Data.Bool + ) where + +--import Prelude () +import Prelude hiding ( + catch, ioError, appendFile, foldr, all, and, any, concat, concatMap, elem, + foldl, foldr1, notElem, or, mapM, sequence, mapM_, sequence_, foldl1, + maximum, minimum, product, sum, id,(.)) +import Control.Applicative +import Control.Arrow +import Control.Exception +import Control.Monad hiding ( + mapM,sequence,forM,mapM_,sequence_,forM_,msum,Monad(..),(=<<),Functor(..)) +import Data.Traversable +import Data.Foldable +import Data.Monoid hiding (Sum(..)) +import Data.List hiding ( + foldr,all,and,any,concat,concatMap,elem,foldl,foldr1 + , notElem,or,foldl1,maximum,minimum,product,sum,find,foldl' + , maximumBy,minimumBy,mapAccumL,mapAccumR,null + , (++),map,(!!),break,cycle,drop,dropWhile,filter + , head,init,iterate,last,length,lookup,repeat,replicate + , reverse,scanl,scanl1,scanr,scanr1,span,splitAt,tail,take + , takeWhile,unzip,unzip3,zip,zip3,zipWith,zipWith3,lines + , unlines,unwords,words ) +import Data.Function hiding ((.),($),const,flip,id) +import Data.Ord (comparing) + +--import Prelude.Plus hiding (Sum, dup) +import Control.Category +import Cgm.Control.Combinators +import Cgm.Control.InFunctor +import Cgm.Data.Tagged +import Cgm.Data.Bool + +{-# INLINE counting #-} +counting :: (Num a, Enum a) => a -> [a] +counting a = [0 .. pred a]
+ src/Cgm/System/Endian.hs view
@@ -0,0 +1,117 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE TemplateHaskell, TypeFamilies, GeneralizedNewtypeDeriving, ScopedTypeVariables #-} + +module Cgm.System.Endian ( + Endian(..), + swapHalves, + ixBytes, + littleEndianIxBytes, + bigEndianIxBytes, + platformEndianness, + platformWordEndianness, + ByteSwapped, + swapBytes, + unswapBytes, + Endianness(..), + reverseEndianness + ) where + +import Data.Bits +import Data.Ix +import Control.Applicative +import Foreign.Marshal.Alloc +import Foreign.Ptr +import Foreign.Storable +import Cgm.Data.Tagged +import Cgm.Data.Word +import Cgm.Data.Array +import Cgm.Data.Len +import Cgm.Data.Structured +import Cgm.Control.InFunctor +import Cgm.Control.Combinators + +class (Prim w, Bits w) => Endian w where + untypedSwapBytes :: w -> w + +instance Endian Word8 where + {-# INLINE untypedSwapBytes #-} + untypedSwapBytes = id +instance Endian Word16 where + {-# INLINE untypedSwapBytes #-} + untypedSwapBytes = swapHalves +instance Endian Word32 where + {-# INLINE untypedSwapBytes #-} + untypedSwapBytes = swapMask 0xff00ff 8 . swapHalves +instance Endian Word64 where + {-# INLINE untypedSwapBytes #-} + untypedSwapBytes = swapMask 0xff00ff00ff00ff 8 . swapMask 0xffff0000ffff 16 . swapHalves +instance Endian Word where + {-# INLINE untypedSwapBytes #-} + untypedSwapBytes = onWordConvB (flip liftItI untypedSwapBytes) (flip liftItI untypedSwapBytes) + + +{-# INLINE swapHalves #-} +swapHalves :: forall w. Bits w => w -> w +swapHalves w = w `shiftR` halfBitSize + w `shiftL` halfBitSize where + halfBitSize = bitSize (undefined :: w) `div` 2 + +{-# INLINE swapMask #-} +swapMask :: Bits w => w -> Int -> w -> w +swapMask mask shift w = ((w `shiftR` shift) .&. mask) + ((w .&. mask) `shiftL` shift) + +-- Number with byte value n in the nth byte, in order of increasing significance (starting at 0) +byteNumbers :: forall w. Endian w => w +byteNumbers = sum $ fmap (\n -> fromIntegral n `shiftL` (8 * fromIntegral n)) $ (at :: At w) increasingBytes + +increasingBytes :: forall w. Prim w => Tagged w [Word8] +increasingBytes = Tagged $ range (0, fromIntegral (primSizeOf (undefined :: w)) - 1) + +singletonArray :: Prim w => w -> PrimArray Free w +singletonArray w = runSTPrimArray (mkArray 1 >>= \a -> a <$ writeArray a 0 w) + +-- Indexes each byte of a word +ixBytes :: forall w. Endian w => w -> [Word8] +ixBytes w = let a = unsafePrimArrayCast (singletonArray w) :: PrimArray Free Word8 in indexArray a . unsafeLen . fromIntegral <$> (at :: At w) increasingBytes + +littleEndianIxBytes :: forall w. Prim w => Tagged w [Word8] +littleEndianIxBytes = increasingBytes +bigEndianIxBytes :: forall w. Prim w => Tagged w [Word8] +bigEndianIxBytes = reverse <$> increasingBytes + +data Endianness = LittleEndian | BigEndian deriving (Eq, Show) + +-- | Undefined when the platform is neither big nor little endian. +{-# SPECIALIZE platformEndianness :: Tagged Word32 Endianness #-} +{-# SPECIALIZE platformEndianness :: Tagged Word64 Endianness #-} +{-# SPECIALIZE platformEndianness :: Tagged Word Endianness #-} +platformEndianness :: forall w. Endian w => Tagged w Endianness +platformEndianness = do + let plat = ixBytes (byteNumbers :: w) + l <- littleEndianIxBytes + b <- bigEndianIxBytes + if plat == l then return LittleEndian else if plat == b then return BigEndian else undefined + +platformWordEndianness :: Endianness +platformWordEndianness = (at :: At Word) platformEndianness +reverseEndianness LittleEndian = BigEndian +reverseEndianness BigEndian = LittleEndian + +newtype ByteSwapped w = ByteSwapped w deriving (Prim, Show) +swapBytes :: Endian w => w -> ByteSwapped w +swapBytes = ByteSwapped . untypedSwapBytes +unswapBytes :: Endian w => ByteSwapped w -> w +unswapBytes (ByteSwapped w) = untypedSwapBytes w + +deriveStructured ''Endianness
+ src/Cgm/System/Mem/Alloc.hs view
@@ -0,0 +1,67 @@+{- +Copyright 2010-2012 Cognimeta Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in +compliance with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and limitations under the License. +-} + +{-# LANGUAGE FlexibleContexts, TupleSections #-} + +module Cgm.System.Mem.Alloc ( + mallocArrayLen, + copyArrayLen, + advancePtrLen, + minusPtrLen, + pokeLenOff, + peekLenOff, + hPutBufLen, + hGetBufLen + ) where + +import Debug.Trace +import Data.Functor +import Data.Word +import Foreign.Ptr +import Foreign.Storable +import Foreign.Marshal.Array +import System.IO +import Cgm.Data.Len +import Cgm.Control.Combinators + +{-# INLINE mallocArrayLen #-} +mallocArrayLen :: (Storable a, Integral b) => Len a b -> IO (Ptr a) +mallocArrayLen = mallocArray . fromIntegral . getLen + +{-# INLINE copyArrayLen #-} +copyArrayLen :: (Storable a, Integral b) => Ptr a -> Ptr a -> Len a b -> IO () +copyArrayLen dest src = copyArray dest src . fromIntegral . getLen + +{-# INLINE advancePtrLen #-} +advancePtrLen :: (Storable a, Integral b) => Ptr a -> Len a b -> Ptr a +advancePtrLen p = advancePtr p . fromIntegral . getLen + +{-# INLINE minusPtrLen #-} +minusPtrLen :: (LgMultiple a Word8) => Ptr a -> Ptr a -> Len a Int +minusPtrLen a b = fst $ coarseRem (unsafeLen $ a `minusPtr` b :: Len Word8 Int) + +{-# INLINE pokeLenOff #-} +pokeLenOff :: (Show a, Storable a, Integral b) => Ptr a -> Len a b -> a -> IO () +pokeLenOff ptr = pokeElemOff ptr . fromIntegral . getLen + +{-# INLINE peekLenOff #-} +peekLenOff :: (Storable a, Integral b) => Ptr a -> Len a b -> IO a +peekLenOff ptr = peekElemOff ptr . fromIntegral . getLen + +{-# INLINE hPutBufLen #-} +hPutBufLen :: (Storable a, Integral b) => Handle -> Ptr a -> Len a b -> IO () +hPutBufLen h ptr = hPutBuf h ptr . fromIntegral . getLen + +{-# INLINE hGetBufLen #-} +hGetBufLen :: (Storable a, Integral b) => Handle -> Ptr a -> Len a b -> IO (Len a b) +hGetBufLen h ptr = ((unsafeLen . fromIntegral) <$>) . hGetBuf h ptr . fromIntegral . getLen
+ src/Cgm/TH/Label.hs view
@@ -0,0 +1,25 @@+{-+Copyright 2010-2012 Cognimeta Inc.++Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in+compliance with the License. You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software distributed under the License is+distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+or implied. See the License for the specific language governing permissions and limitations under the License.+-}++{-# LANGUAGE TemplateHaskell #-}++module Cgm.TH.Label (+ label+) where++import Language.Haskell.TH++label :: Name -> ExpQ+label s = [|($(return $ LitE $ stringL $ nameBase s),$(varE s))|]++