Shpadoinkle-lens (empty) → 0.0.0.1
raw patch · 4 files changed
+183/−0 lines, 4 filesdep +Shpadoinkledep +basedep +lenssetup-changed
Dependencies added: Shpadoinkle, base, lens, text
Files
- LICENSE +27/−0
- Setup.hs +2/−0
- Shpadoinkle-lens.cabal +32/−0
- Shpadoinkle/Lens.hs +122/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Shpadoinkle Lens aka S11 Lens+Copyright © 2020 Isaac Shapira+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ * Neither the name of Shpadoinkle nor the names of its contributors may be+ used to endorse or promote products derived from this software without+ specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Shpadoinkle-lens.cabal view
@@ -0,0 +1,32 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.32.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: ebcb50534c3fd9629e258370d8be4b17cb04e004d5b3320e96d3226e1b500716++name: Shpadoinkle-lens+version: 0.0.0.1+description: Lens combinators for Shpadoinkle applications.+category: Web+author: Isaac Shapira+maintainer: fresheyeball@protonmail.com+license: BSD3+license-file: LICENSE+build-type: Simple++library+ exposed-modules:+ Shpadoinkle.Lens+ other-modules:+ Paths_Shpadoinkle_lens+ hs-source-dirs:+ ./.+ ghc-options: -Wall -Wcompat -fwarn-redundant-constraints -fwarn-incomplete-uni-patterns -fwarn-tabs -fwarn-incomplete-record-updates -fwarn-identities+ build-depends:+ Shpadoinkle+ , base >=4.12.0 && <4.16+ , lens >=4.17.1 && <4.2+ , text >=1.2.3 && <1.3+ default-language: Haskell2010
+ Shpadoinkle/Lens.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE RankNTypes #-}+++{-|+ Lens combinators for Shpadoinkle applications.+-}+++module Shpadoinkle.Lens (+ -- * Continuous Composition+ generalize+ , onSum, onRecord+ , mapLens, (%>)+ , forLens, (<%)+ -- * Misc Outlaws+ , rounding, defaulting, fracIntegral+ ) where+++import Control.Lens+import Data.Maybe+import Shpadoinkle.Continuation+++generalize, onRecord :: forall f m s a. Functor m => Continuous f => Lens' s a -> f m a -> f m s+{-|+ Compose multiple Shpadoinkle views onto a product type, most frequently a record.+ Let's say we have @Html@ which produces 'Int's, and we need to use it in a view+ with more components. The model for such a view might be @(Int, String)@. To use+ our child @Html@ inside the parent, we can assign produced @Int@s to the parent+ tuple by using the '_1' lens like so:++ @+ child :: Html Int++ parent :: Html (Int, String)+ parent = div_+ [ button [ onClick (0, \"Reset\") [ text "Reset!" ]+ , generalize _1 child+ ]+ @+-}+generalize len = liftC (set len) (view len)+{-|+ Alias for 'generalize' with a name idiomatic to the common case of composing onto a record.+-}+onRecord = generalize+{-# INLINE onRecord #-}+{-# INLINE generalize #-}+++{-|+ Split multiple Shpadoinkle views over a sum type. This is commonly the case when+ using a sum to represent pages in a single page application, but it's useful for+ any sum. For example, consider that you have a view with a model of @Either Int String@+ and a child @Html@ that produces 'Int's. You can compose this child onto the parent+ using '_Left' traversal like so:++ @+ child :: Html Int++ parent :: Html (Either Int String)+ parent = div_+ [ button [ onClick (Right \"Reset\") ] [ text "Reset!" ]+ , onSum _Left child+ ]+ @+-}+onSum :: forall f m s a. Applicative m => Continuous f => Traversal' s a -> f m a -> f m s+onSum p = liftCMay (set p) (preview p)+{-# INLINE onSum #-}+++infixl 8 <%+infixr 8 %>+++forLens, (<%) :: forall f m s a. Functor m => Continuous f => s -> Lens' s a -> (a -> f m a) -> f m s+{-|+ A variant of 'generalize' for the case where you might need to map the smaller value.++ @+ parent :: Html (Int, String)+ parent model = div_+ [ forLens model _1 $ \(i :: Int) ->+ if i < 10 then text \"too low\" else+ button [ onClick (i + 1) ] [ text \"Increment\" ]+ ]+ @+-}+forLens big len f = generalize len . f $ view len big+-- | Infix for 'forLens'+(<%) = forLens+{-# INLINE forLens #-}+{-# INLINE (<%) #-}+++mapLens, (%>) :: forall f m s a. Functor m => Continuous f => (a -> f m a) -> s -> Lens' s a -> f m s+{-|+ Like 'forLens' but with the lambda as the first argument.+-}+mapLens f big len = forLens big len f+-- | Infix for 'mapLens'+(%>) = mapLens+{-# INLINE mapLens #-}+{-# INLINE (%>) #-}+++fracIntegral :: forall s a. Integral a => RealFrac s => Prism' s a+fracIntegral = prism fromIntegral $+ \f -> let r = round f in+ if fromIntegral r == f then Right r else Left f+++rounding :: forall a s. Integral s => RealFrac a => Iso' s a+rounding = iso fromIntegral round+{-# INLINE rounding #-}+++defaulting :: a -> Iso' (Maybe a) a+defaulting x = iso (fromMaybe x) Just+{-# INLINE defaulting #-}