named 0.2.0.0 → 0.4.0.0
raw patch · 7 files changed
Files
- ChangeLog.md +18/−0
- LICENSE +2/−1
- named.cabal +16/−11
- src/Named.hs +38/−9
- src/Named/Internal.hs +37/−21
- test/Test.hs +90/−15
- test/TestImport.hs +3/−0
ChangeLog.md view
@@ -1,3 +1,21 @@+## 0.4.0.0++* Support GHCs 9.6 to 9.14.+* Fix conflict with 'generic-lens' by using '{-# OVERLAPPING #-}'.++## 0.3.0.2++* Support GHCs 9.4 to 9.10, fix warnings.++## 0.3.0.1++* Bumped upper bounds for GHC 8.8.++## 0.3.0.0++* Added 'param', 'paramF'.+* Export 'NamedF(Arg, ArgF)' as a bundle.+ ## 0.2.0.0 * Removed 'Flag', 'named', 'Apply', 'apply'.
LICENSE view
@@ -1,4 +1,5 @@ Copyright (c) 2018, Vladislav Zavialov+ 2018, Monadfix All rights reserved. @@ -13,7 +14,7 @@ disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of Vladislav Zavialov nor the names of other+ * Neither the name of Monadfix nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission.
named.cabal view
@@ -1,5 +1,6 @@+cabal-version: 2.4 name: named-version: 0.2.0.0+version: 0.4.0.0 synopsis: Named parameters (keyword arguments) for Haskell description: `named` is a lightweight library for named function parameters (keyword@@ -28,34 +29,38 @@ > ! #to "/target/path" -license: BSD3+license: BSD-3-Clause license-file: LICENSE author: Vladislav Zavialov-maintainer: Vladislav Zavialov <vlad.z.4096@gmail.com>+maintainer: Monadfix <hi@monadfix.com>+homepage: https://github.com/monadfix/named+bug-reports: https://github.com/monadfix/named/issues category: Control build-type: Simple extra-source-files: ChangeLog.md-tested-with: GHC ==8.0.2, GHC ==8.2.2, GHC ==8.4.1-cabal-version: >=1.10+tested-with: GHC ==9.6.6, GHC ==9.10.3, GHC ==9.12.4, GHC ==9.14.1 source-repository head type: git- location: git@github.com:int-index/named.git+ location: git@github.com:monadfix/named.git library exposed-modules: Named, Named.Internal- build-depends: base >=4.9 && <4.12+ build-depends: base >=4.16 && <4.23 hs-source-dirs: src- default-language: Haskell2010+ default-language: GHC2021 ghc-options: -Wall -fno-warn-unticked-promoted-constructors test-suite regression type: exitcode-stdio-1.0 main-is: Test.hs- build-depends: base >=4.9 && <4.12,- named+ other-modules: TestImport+ build-depends: base >=4.16 && <4.23,+ named,+ generic-lens,+ inspection-testing hs-source-dirs: test- default-language: Haskell2010+ default-language: GHC2021 ghc-options: -Wall -fno-warn-missing-signatures
src/Named.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE PatternSynonyms, ExplicitNamespaces #-}+{-# LANGUAGE ExplicitNamespaces #-} {- | @@ -9,6 +9,8 @@ * readability: their names serve as documentation at call site * safety: it is impossible to accidentally mix them up +The required extensions are @OverloadedLabels@, @DataKinds@, and @TypeOperators@.+ Consider a function to replace a substring with another string: @@@ -44,7 +46,7 @@ '!' \#replacement "\/home\/username\/" @ -Functions can declare their parameter names in pattern bindings:+Functions can declare their parameter names in pattern bindings (via the extension @ViewPatterns@): @ replace ('arg' \#needle -> n) ('arg' \#replacement -> r) ('arg' \#haystack -> h) =@@ -151,26 +153,53 @@ '!' #handle logfile @ += An issue with polymorphic return types++A limitation of 'defaults' is that it is not possible to pass it to a function with a polymorphic return type. In particular: to mtl-style functions. The following code produces a compilation error:++@+foo :: "x" ':?' Int -> m Int++bar :: m Int+bar = foo '!' 'defaults'+@++A workaround is to return a newtype wrapper around @m@:++@+newtype M m a = M { runM :: m a }+ deriving (Functor, Applicative, Monad)++foo :: "x" ':?' Int -> M m Int++bar :: M m Int+bar = foo '!' 'defaults'++bar' :: m Int+bar' = runM (foo '!' 'defaults')+@++Note: the type signature of 'bar' is required.++See [issue #15](https://github.com/monadfix/named/issues/15) "Problem with type inference caused by @! defaults@" for details. -} module Named (- -- * Calling functions+ -- * Call site (!), WithParam(..),+ param,+ paramF, defaults, - -- * Types+ -- * Definition site type (:!), type (:?),- NamedF,-- -- * Patterns+ NamedF(Arg, ArgF), Name(..), arg, argDef, argF,- pattern Arg,- pattern ArgF, ) where import Named.Internal
src/Named/Internal.hs view
@@ -1,8 +1,6 @@-{-# LANGUAGE KindSignatures, DataKinds, FlexibleInstances, FlexibleContexts,- FunctionalDependencies, TypeFamilies, TypeOperators,- PatternSynonyms, UndecidableInstances, ConstraintKinds,- TypeApplications, ScopedTypeVariables, CPP,- AllowAmbiguousTypes #-}+{-# LANGUAGE AllowAmbiguousTypes, DataKinds, ExplicitNamespaces,+ FunctionalDependencies, PatternSynonyms, TypeFamilies,+ UndecidableInstances #-} module Named.Internal where @@ -12,6 +10,7 @@ import Data.Kind (Type) import GHC.TypeLits (Symbol, TypeError, ErrorMessage(..)) import GHC.OverloadedLabels (IsLabel(..))+import Data.Type.Equality (type (~)) {- | @@ -29,10 +28,7 @@ -- | Match on an argument without specifying its name. See also: 'arg'. pattern Arg :: a -> name :! a pattern Arg a = ArgF (Identity a)--#if MIN_VERSION_base(4,10,0) {-# COMPLETE Arg #-}-#endif -- | Infix notation for the type of a named parameter. type name :! a = NamedF Identity a name@@ -50,23 +46,47 @@ injValue = Just instance (name ~ name', a ~ a', InjValue f) => IsLabel name (a -> NamedF f a' name') where-#if MIN_VERSION_base(4,10,0) fromLabel a = ArgF (injValue a)-#else- fromLabel _ a = ArgF (injValue a)-#endif {-# INLINE fromLabel #-} newtype Param p = Param p -instance (p ~ NamedF f a name, InjValue f) => IsLabel name (a -> Param p) where-#if MIN_VERSION_base(4,10,0)+-- It needs to be OVERLAPPING to avoid conflicts with 'generic-lens'.+-- See the discussion for more context: https://github.com/monadfix/named/issues/8+instance {-# OVERLAPPING #-} (p ~ NamedF f a name, InjValue f) => IsLabel name (a -> Param p) where fromLabel a = Param (fromLabel @name a)-#else- fromLabel pName a = Param (fromLabel pName a)-#endif {-# INLINE fromLabel #-} +{- | Explicitly build a function parameter:++@+fn '!' 'param' \#param_name value+@++This is equivalent to the implicit notation:++@+fn '!' \#param_name value+@++-}+param :: Name name -> a -> Param (name :! a)+param _ a = Param (Arg a)++{- | Explicitly build a function parameter inside an arity wrapper:++@+fn '!' 'paramF' \#param_name ('Identity' value)+fn '!' 'paramF' \#param_name ('Just' value)+fn '!' 'paramF' \#param_name 'Nothing'+@++This has no equivalent implicit notation.++-}+paramF :: Name name -> f a -> Param (NamedF f a name)+paramF _ fa = Param (ArgF fa)+ {- | Supply a parameter to a function: @@@ -151,11 +171,7 @@ data Name (name :: Symbol) = Name instance name ~ name' => IsLabel name' (Name name) where-#if MIN_VERSION_base(4,10,0) fromLabel = Name-#else- fromLabel _ = Name-#endif {-# INLINE fromLabel #-} {- |
test/Test.hs view
@@ -1,22 +1,31 @@ {-# LANGUAGE OverloadedLabels, DataKinds, TypeOperators, ViewPatterns,- PartialTypeSignatures #-}+ PartialTypeSignatures, TemplateHaskell #-} {-# OPTIONS -fno-warn-partial-type-signatures #-} module Main where import Data.Maybe (fromMaybe)+import Data.Functor (void) import Data.Function ((&))+import Data.Generics.Labels () -- to ensure our instances won't conflict with IsLabel from generic-lens import Named+import Test.Inspection test1 :: String -> "a" :! Bool -> "b" :! Bool ->- IO ()-test1 "str" (arg #a -> True) (arg #b -> False) = return ()-test1 _ _ _ = error "unexpected flags or str"+ IO Bool+test1 "str" (arg #a -> True) (arg #b -> False) = return True+test1 _ _ _ = return False +test1_raw :: String -> Bool -> Bool -> IO Bool+test1_raw "str" True False = return True+test1_raw _ _ _ = return False++inspect $ 'test1 ==- 'test1_raw+ test1_1 = test1 "str" ! #a True@@ -48,11 +57,20 @@ test2 :: "x" :! Int -> Int test2 x = arg #x x * 2 +test2_raw :: Int -> Int+test2_raw x = x * 2++inspect $ 'test2 ==- 'test2_raw+ test2_1 :: Int test2_1 = test2 ! #x 5 + test2 ! #x 3 test3 (arg #a -> a) (arg #b -> b) = a + b +test3_raw a b = a + b++inspect $ 'test3 ==- 'test3_raw+ -- must not typecheck: -- Couldn't match type ‘"a"’ with ‘"b"’ -- arising from the overloaded label ‘#b’@@ -60,35 +78,92 @@ -- test3' :: _ => "a" :! _ -> _ :! "b" -> _ -- test3' (arg #b -> a) (arg #a -> b) = a + b --- test4 ::--- "b" :! Bool ->--- NamedF _ Char "x" ->--- "y" :? Char ->--- Char+test4 ::+ "b" :! Bool ->+ NamedF _ Char "x" ->+ "y" :? Char ->+ Char test4 (arg #b -> b) (argDef #x 'x' -> x) (ArgF y) = if b then x else (fromMaybe 'y' y) +test4_raw :: Bool -> Maybe Char -> Maybe Char -> Char+test4_raw b (fromMaybe 'x' -> x) y = if b then x else fromMaybe 'y' y++inspect $ 'test4 ==- 'test4_raw+ test4_1 = test4 ! #b True ! defaults test4_2 = test4 ! #b False ! defaults test4_3 = test4 ! #x 'z' ! #b True ! defaults test4_4 = test4 ! defaults ! #b True+test4_5 = test4 ! paramF #x (Just 'q') ! #b True ! defaults+test4_6 = test4 ! paramF #x Nothing ! #b True ! #y '-' +test5_1 :: ("bar" :! Int -> ()) -> ()+test5_1 f = f ! #bar 3++test5_1_raw :: (Int -> ()) -> ()+test5_1_raw f = f 3++inspect $ 'test5_1 ==- 'test5_1_raw++test5_2 :: ("bar" :! Int -> ()) -> "bar" :! Int -> ()+test5_2 f x = f x++test5_2_raw :: (Int -> ()) -> Int -> ()+test5_2_raw f x = f x++inspect $ 'test5_2 ==- 'test5_2_raw++test6 :: Maybe ("x" :! Int -> Int) -> Int+test6 Nothing = 0+test6 (Just f) = f ! #x 42++test6_raw :: Maybe (Int -> Int) -> Int+test6_raw Nothing = 0+test6_raw (Just f) = f 42++inspect $ 'test6 ==- 'test6_raw++newtype M m a = M { runM :: m a }+ deriving (Functor, Applicative, Monad)++-- must typecheck:++test7_1 :: "x" :? Int -> M m Int+test7_1 = undefined++test7_2 :: M m Int+test7_2 = test7_1 ! defaults++test7_3 :: m Int+test7_3 = runM (test7_1 ! defaults)++-- doesn't typecheck (yet):+--+-- test7_4 :: "x" :? Int -> m Int+-- test7_4 = undefined++-- test7_5 :: m Int+-- test7_5 = test7_1 ! defaults+ main :: IO () main = do- test1_1- test1_2- test1_3- test1_4- test1_5- test1_6+ void test1_1+ void test1_2+ void test1_3+ void test1_4+ void test1_5+ void test1_6 test2_1 `mustBe` 16 test4_1 `mustBe` 'x' test4_2 `mustBe` 'y' test4_3 `mustBe` 'z' test4_4 `mustBe` 'x'+ test4_5 `mustBe` 'q'+ test4_6 `mustBe` 'x' mustBe :: (Eq a, Show a) => a -> a -> IO () mustBe a b
+ test/TestImport.hs view
@@ -0,0 +1,3 @@+module TestImport (module Named) where++import Named (NamedF(Arg, ArgF))