Skip to content

Commit

Permalink
[serokell#265] Make SuperComposition less brittle
Browse files Browse the repository at this point in the history
* Use overlapping instances instead of incoherent ones. Fixes serokell#265.

* Make the first argument of `...` a function unconditionally, before
  instance selection. This can theoretically improve inference slightly,
  though it probably doesn't have much impact in practice.
  • Loading branch information
treeowl committed May 9, 2022
1 parent 86b30df commit 078a5ca
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Unreleased
=====

* [#265](https://github.com/serokell/universum/issues/265):
Make `SuperComposition` inference less brittle, and give it four
type parameters.

* [#252](https://github.com/serokell/universum/pull/252):
Remove `Option` re-export. Use `Maybe` instead.

Expand Down
2 changes: 1 addition & 1 deletion benchmark/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ bgroupSuperComposition = bgroup "(...)"
where
super10 :: [()] -> Bool
super10 = null
... ((: []) ... Unsafe.head ... pure ... Unsafe.head
... ((: []) ... Unsafe.head ... (:[]) ... Unsafe.head
... (: [(), (), (), ()]) ... Unsafe.head ... (: []) ... Unsafe.head
... (: [()]) ... Unsafe.head ... (: [(), ()]) ... Unsafe.head :: [()] -> [()])

Expand Down
20 changes: 12 additions & 8 deletions src/Universum/VarArg.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ module Universum.VarArg
-- >>> import Data.List (zip5)

-- | This type class allows to implement variadic composition operator.
class SuperComposition a b c | a b -> c where
class SuperComposition x y b r | x y b -> r where
-- | Allows to apply function to result of another function with multiple
-- arguments.
--
-- >>> (show ... (+)) 1 2
-- >>> (show ... (+)) (1 :: Int) 2
-- "3"
-- >>> show ... 5
-- >>> show ... (5 :: Int)
-- "5"
-- >>> (null ... zip5) [1] [2] [3] [] [5]
-- True
--
-- Note that the arity of the second argument must be apparent to the type
-- checker, which is why the above examples require type annotations for numeric
-- literals.
--
-- Inspired by <http://stackoverflow.com/questions/9656797/variadic-compose-function>.
--
-- ==== Performance
Expand All @@ -45,16 +49,16 @@ class SuperComposition a b c | a b -> c where
-- disappear due to very general inferred type. However, functions without type
-- specification but with applied @INLINE@ pragma are fast again.
--
(...) :: a -> b -> c
(...) :: (x -> y) -> b -> r

infixl 8 ...

instance {-# INCOHERENT #-} (a ~ c, r ~ b) =>
SuperComposition (a -> b) c r where
instance {-# OVERLAPPABLE #-} (x ~ b, y ~ r) =>
SuperComposition x y b r where
f ... g = f g
{-# INLINE (...) #-}

instance {-# INCOHERENT #-} (SuperComposition (a -> b) d r1, r ~ (c -> r1)) =>
SuperComposition (a -> b) (c -> d) r where
instance {-# OVERLAPPING #-} (SuperComposition x y d r1, r ~ (c -> r1)) =>
SuperComposition x y (c -> d) r where
(f ... g) c = f ... g c
{-# INLINE (...) #-}

0 comments on commit 078a5ca

Please sign in to comment.