{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}

{- |
Module      : Primus.Extra
Description : miscellaneous functions
Copyright   : (c) Grant Weyburne, 2022
License     : BSD-3
-}
module Primus.Extra (
  on1,
  on2,
  comparing1,
  (.@),
) where

-- | more flexible version of 'Data.Function.on' that allows differing types for the same container
on1 ::
  forall f a a' b c.
  (b -> b -> c) ->
  (forall x. f x -> b) ->
  f a ->
  f a' ->
  c
on1 :: (b -> b -> c) -> (forall (x :: k). f x -> b) -> f a -> f a' -> c
on1 b -> b -> c
f forall (x :: k). f x -> b
g f a
fa f a'
fa' = b -> b -> c
f (f a -> b
forall (x :: k). f x -> b
g f a
fa) (f a' -> b
forall (x :: k). f x -> b
g f a'
fa')

-- | more flexible version of 'Data.Function.on' that allows differing types for the same container but using two parameters
on2 ::
  forall f a a' a2 a2' b c.
  (b -> b -> c) ->
  (forall x y. f x y -> b) ->
  f a a2 ->
  f a' a2' ->
  c
on2 :: (b -> b -> c)
-> (forall (x :: k) (y :: k). f x y -> b)
-> f a a2
-> f a' a2'
-> c
on2 b -> b -> c
f forall (x :: k) (y :: k). f x y -> b
g f a a2
fa f a' a2'
fa' = b -> b -> c
f (f a a2 -> b
forall (x :: k) (y :: k). f x y -> b
g f a a2
fa) (f a' a2' -> b
forall (x :: k) (y :: k). f x y -> b
g f a' a2'
fa')

-- | more flexible version of 'compare' that allows differing types for the same container
comparing1 ::
  forall f a a' b.
  Ord b =>
  (forall x. f x -> b) ->
  f a ->
  f a' ->
  Ordering
comparing1 :: (forall (x :: k). f x -> b) -> f a -> f a' -> Ordering
comparing1 forall (x :: k). f x -> b
g f a
fa f a'
fa' = b -> b -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (f a -> b
forall (x :: k). f x -> b
g f a
fa) (f a' -> b
forall (x :: k). f x -> b
g f a'
fa')

-- | compose a two arg function followed by a one arg function
(.@) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
.@ :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.@) = ((b -> c) -> b -> d) -> (a -> b -> c) -> a -> b -> d
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) (((b -> c) -> b -> d) -> (a -> b -> c) -> a -> b -> d)
-> ((c -> d) -> (b -> c) -> b -> d)
-> (c -> d)
-> (a -> b -> c)
-> a
-> b
-> d
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (c -> d) -> (b -> c) -> b -> d
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.)

infixr 8 .@