named 0.3.0.2 → 0.4.0.0
raw patch · 5 files changed
+118/−17 lines, 5 filesdep +generic-lensdep +inspection-testingdep ~base
Dependencies added: generic-lens, inspection-testing
Dependency ranges changed: base
Files
- ChangeLog.md +5/−0
- named.cabal +7/−5
- src/Named.hs +32/−1
- src/Named/Internal.hs +3/−1
- test/Test.hs +71/−10
ChangeLog.md view
@@ -1,3 +1,8 @@+## 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.
named.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: named-version: 0.3.0.2+version: 0.4.0.0 synopsis: Named parameters (keyword arguments) for Haskell description: `named` is a lightweight library for named function parameters (keyword@@ -38,7 +38,7 @@ category: Control build-type: Simple extra-source-files: ChangeLog.md-tested-with: GHC ==9.4.8, GHC ==9.6.6, GHC ==9.10.1+tested-with: GHC ==9.6.6, GHC ==9.10.3, GHC ==9.12.4, GHC ==9.14.1 source-repository head type: git@@ -46,7 +46,7 @@ library exposed-modules: Named, Named.Internal- build-depends: base >=4.16 && <4.21+ build-depends: base >=4.16 && <4.23 hs-source-dirs: src default-language: GHC2021 ghc-options: -Wall@@ -56,8 +56,10 @@ type: exitcode-stdio-1.0 main-is: Test.hs other-modules: TestImport- build-depends: base >=4.16 && <4.21,- named+ build-depends: base >=4.16 && <4.23,+ named,+ generic-lens,+ inspection-testing hs-source-dirs: test default-language: GHC2021 ghc-options: -Wall
src/Named.hs view
@@ -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,6 +153,35 @@ '!' #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 (
src/Named/Internal.hs view
@@ -51,7 +51,9 @@ newtype Param p = Param p -instance (p ~ NamedF f a name, InjValue f) => IsLabel name (a -> Param p) where+-- 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) {-# 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’@@ -71,6 +89,11 @@ (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@@ -81,21 +104,59 @@ 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'