{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Functor
-- Copyright   :  (c) The University of Glasgow 2001
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  portable
--
--
-- A type @f@ is a Functor if it provides a function @fmap@ which, given any types @a@ and @b@,
-- lets you apply any function of type @(a -> b)@ to turn an @f a@ into an @f b@, preserving the
-- structure of @f@.
--
-- ==== __Examples__
--
--  >>> fmap show (Just 1)  --  (a   -> b)      -> f a       -> f b
--  Just "1"                --  (Int -> String) -> Maybe Int -> Maybe String
--
--  >>> fmap show Nothing   --  (a   -> b)      -> f a       -> f b
--  Nothing                 --  (Int -> String) -> Maybe Int -> Maybe String
--
--  >>> fmap show [1,2,3]   --  (a   -> b)      -> f a       -> f b
--  ["1","2","3"]           --  (Int -> String) -> [Int]     -> [String]
--
--  >>> fmap show []        --  (a   -> b)      -> f a       -> f b
--  []                      --  (Int -> String) -> [Int]     -> [String]
--
-- The 'fmap' function is also available as the infix operator '<$>':
--
--  >>> fmap show (Just 1) --  (Int -> String) -> Maybe Int -> Maybe String
--  Just "1"
--  >>> show <$> (Just 1)  --  (Int -> String) -> Maybe Int -> Maybe String
--  Just "1"

module Data.Functor
    (
      Functor(..),
      ($>),
      (<$>),
      (<&>),
      unzip,
      void,
    ) where

import GHC.Base ( Functor(..), flip )
import Data.Tuple ( fst, snd )

-- $setup
-- Allow the use of Prelude in doctests.
-- >>> import Prelude hiding ((<$>))

infixl 4 <$>

-- | An infix synonym for 'fmap'.
--
-- The name of this operator is an allusion to 'Prelude.$'.
-- Note the similarities between their types:
--
-- >  ($)  ::              (a -> b) ->   a ->   b
-- > (<$>) :: Functor f => (a -> b) -> f a -> f b
--
-- Whereas 'Prelude.$' is function application, '<$>' is function
-- application lifted over a 'Functor'.
--
-- ==== __Examples__
--
-- Convert from a @'Data.Maybe.Maybe' 'Data.Int.Int'@ to a @'Data.Maybe.Maybe'
-- 'Data.String.String'@ using 'Prelude.show':
--
-- >>> show <$> Nothing
-- Nothing
-- >>> show <$> Just 3
-- Just "3"
--
-- Convert from an @'Data.Either.Either' 'Data.Int.Int' 'Data.Int.Int'@ to an
-- @'Data.Either.Either' 'Data.Int.Int'@ 'Data.String.String' using 'Prelude.show':
--
-- >>> show <$> Left 17
-- Left 17
-- >>> show <$> Right 17
-- Right "17"
--
-- Double each element of a list:
--
-- >>> (*2) <$> [1,2,3]
-- [2,4,6]
--
-- Apply 'Prelude.even' to the second element of a pair:
--
-- >>> even <$> (2,2)
-- (2,True)
--
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<$>) = fmap

infixl 1 <&>

-- | Flipped version of '<$>'.
--
-- @
-- ('<&>') = 'flip' 'fmap'
-- @
--
-- @since 4.11.0.0
--
-- ==== __Examples__
-- Apply @(+1)@ to a list, a 'Data.Maybe.Just' and a 'Data.Either.Right':
--
-- >>> Just 2 <&> (+1)
-- Just 3
--
-- >>> [1,2,3] <&> (+1)
-- [2,3,4]
--
-- >>> Right 3 <&> (+1)
-- Right 4
--
(<&>) :: Functor f => f a -> (a -> b) -> f b
as <&> f = f <$> as

infixl 4 $>

-- | Flipped version of '<$'.
--
-- @since 4.7.0.0
--
-- ==== __Examples__
--
-- Replace the contents of a @'Data.Maybe.Maybe' 'Data.Int.Int'@ with a constant
-- 'Data.String.String':
--
-- >>> Nothing $> "foo"
-- Nothing
-- >>> Just 90210 $> "foo"
-- Just "foo"
--
-- Replace the contents of an @'Data.Either.Either' 'Data.Int.Int' 'Data.Int.Int'@
-- with a constant 'Data.String.String', resulting in an @'Data.Either.Either'
-- 'Data.Int.Int' 'Data.String.String'@:
--
-- >>> Left 8675309 $> "foo"
-- Left 8675309
-- >>> Right 8675309 $> "foo"
-- Right "foo"
--
-- Replace each element of a list with a constant 'Data.String.String':
--
-- >>> [1,2,3] $> "foo"
-- ["foo","foo","foo"]
--
-- Replace the second element of a pair with a constant 'Data.String.String':
--
-- >>> (1,2) $> "foo"
-- (1,"foo")
--
($>) :: Functor f => f a -> b -> f b
($>) = flip (<$)

-- | Generalization of @Data.List.@'Data.List.unzip'.
--
-- @since 4.19.0.0
unzip :: Functor f => f (a, b) -> (f a, f b)
unzip xs = (fst <$> xs, snd <$> xs)

-- | @'void' value@ discards or ignores the result of evaluation, such
-- as the return value of an 'System.IO.IO' action.
--
-- ==== __Examples__
--
-- Replace the contents of a @'Data.Maybe.Maybe' 'Data.Int.Int'@ with unit:
--
-- >>> void Nothing
-- Nothing
-- >>> void (Just 3)
-- Just ()
--
-- Replace the contents of an @'Data.Either.Either' 'Data.Int.Int' 'Data.Int.Int'@
-- with unit, resulting in an @'Data.Either.Either' 'Data.Int.Int' '()'@:
--
-- >>> void (Left 8675309)
-- Left 8675309
-- >>> void (Right 8675309)
-- Right ()
--
-- Replace every element of a list with unit:
--
-- >>> void [1,2,3]
-- [(),(),()]
--
-- Replace the second element of a pair with unit:
--
-- >>> void (1,2)
-- (1,())
--
-- Discard the result of an 'System.IO.IO' action:
--
-- >>> mapM print [1,2]
-- 1
-- 2
-- [(),()]
-- >>> void $ mapM print [1,2]
-- 1
-- 2
--
void :: Functor f => f a -> f ()
void x = () <$ x
