-- |
-- Module : Data.DoubleZip
-- Copyright : (c) OleksandrZhabenko 2020-2021
-- License : MIT
-- Stability : Experimental
-- Maintainer : olexandr543@yahoo.com
--
-- Some special functions to work with lists (with zip).
{-# OPTIONS_GHC -threaded #-}
module Data.DoubleZip (
normFst
, normSnd
, evalFstFV
, evalFstFVM
, evalSndFV
, evalSndFVM
, double42Float4
, float42Double4
) where
import GHC.Float (double2Float,float2Double)
import qualified Data.List as L
import Data.Foldable.Ix (s2L)
-- | Norms a tuples in a list by their first elements so that the greatest by an absolute value first element is equal to 1 (or -1). If all the first
-- elements are zeros then prints a warning message and exits successfully.
normFst :: (Fractional a, Ord a) => [(a, b)] -> IO [(a, b)]
normFst v
| all (\(x,_) -> x == 0) v = putStrLn "Warning: Data.DoubleZip.normFst: List with all zero first parts of the elements." >> return v
| otherwise = mapM (\(x,y) -> return (x / abs (L.maximumBy (\t u -> compare (abs t) (abs u)) . map fst $ v),y)) v
-- | Norms a tuples in a list by their second elements so that the greatest by an absolute value second element is equal to 1 (or -1). If all the second
-- elements are zeros then prints a warning message and exits successfully.
normSnd :: (Fractional b, Ord b) => [(a, b)] -> IO [(a, b)]
normSnd v
| all (\(_,y) -> y == 0) v = putStrLn "Warning: Data.DoubleZip.normSnd: List with all zero second parts of the elements." >> return v
| otherwise = mapM (\(x,y) -> return (x,y / abs (L.maximumBy (\t u -> compare (abs t) (abs u)) . map snd $ v))) v
-- | A special function transformation to obtain the resulting list so that its first elements in the inner tuples are in a special way
-- normed to 1 (or -1) by 'normFst' and the inner tuples are sequenced one by another as a 2D points of the generating function @f :: a -> b@.
-- To obtain non-empty result the given second argument must have at least two elements.
evalFstFV :: (Fractional a, Ord a, Eq b) => (a -> b) -> [a] -> IO [((a, b), (a, b))]
evalFstFV f v
| length v > 1 = do
zipped <- normFst . zip v . map f $ v
return . zip zipped . s2L 1 (length v - 1) $ zipped
| otherwise = return []
-- | The same as 'evalFstFV' but uses a monadic IO function f.
evalFstFVM :: (Fractional a, Ord a, Eq b) => (a -> IO b) -> [a] -> IO [((a, b), (a, b))]
evalFstFVM f v
| length v > 1 = do
v1 <- mapM f v
zipped <- normFst . zip v $ v1
return . zip zipped . s2L 1 (length v - 1) $ zipped
| otherwise = return []
-- | A special function transformation to obtain the resulting list so that its second elements in the inner tuples are in a special way
-- normed to 1 (or -1) by 'normSnd' and the inner tuples are sequenced one by another as a 2D points of the generating function @f :: a -> b@.
-- To obtain non-empty result the given second argument must have at least two elements. Is similar to 'evalFstFV'.
evalSndFV :: (Fractional b, Ord b, Eq a) => (a -> b) -> [a] -> IO [((a, b), (a, b))]
evalSndFV f v
| length v > 1 = do
zipped <- normSnd . zip v . map f $ v
return . zip zipped . s2L 1 (length v - 1) $ zipped
| otherwise = return []
-- | The same as 'evalSndFV' but uses a monadic IO function f.
evalSndFVM :: (Fractional b, Ord b, Eq a) => (a -> IO b) -> [a] -> IO [((a, b), (a, b))]
evalSndFVM f v
| length v > 1 = do
v1 <- mapM f v
zipped <- normSnd . zip v $ v1
return . zip zipped . s2L 1 (length v - 1) $ zipped
| otherwise = return []
double42Float4 :: ((Double,Double), (Double,Double)) -> ((Float,Float), (Float,Float))
double42Float4 ((x,y),(z,t)) = ((double2Float x,double2Float y),(double2Float z,double2Float t))
float42Double4 :: ((Float,Float), (Float,Float)) -> ((Double,Double), (Double,Double))
float42Double4 ((x,y),(z,t)) = ((float2Double x,float2Double y),(float2Double z,float2Double t))