optional-args-1.0.2/0000755000000000000000000000000013240722713012460 5ustar0000000000000000optional-args-1.0.2/LICENSE0000644000000000000000000000275713240722713013500 0ustar0000000000000000Copyright (c) 2015 Gabriel Gonzalez All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Gabriel Gonzalez nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. optional-args-1.0.2/optional-args.cabal0000644000000000000000000000150313240722713016222 0ustar0000000000000000Name: optional-args Version: 1.0.2 Cabal-Version: >=1.10 Build-Type: Simple License: BSD3 License-File: LICENSE Copyright: 2015 Gabriel Gonzalez Author: Gabriel Gonzalez Maintainer: Gabriel439@gmail.com Bug-Reports: https://github.com/Gabriel439/Haskell-Optional-Args-Library/issues Synopsis: Optional function arguments Description: This library provides a type for specifying `Optional` function arguments . Read the tutorial in "Data.Optional" to learn more Category: Data Source-Repository head Type: git Location: https://github.com/Gabriel439/Haskell-Optional-Args-Library Library HS-Source-Dirs: src Build-Depends: base >= 4.5 && < 5 if !impl(ghc >= 8.0) Build-Depends: semigroups >= 0.16 && < 0.19 Exposed-Modules: Data.Optional GHC-Options: -O2 -Wall Default-Language: Haskell2010 optional-args-1.0.2/Setup.hs0000644000000000000000000000005613240722713014115 0ustar0000000000000000import Distribution.Simple main = defaultMain optional-args-1.0.2/src/0000755000000000000000000000000013240722713013247 5ustar0000000000000000optional-args-1.0.2/src/Data/0000755000000000000000000000000013240722713014120 5ustar0000000000000000optional-args-1.0.2/src/Data/Optional.hs0000644000000000000000000001172713240722713016251 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveTraversable #-} -- | Use the `Optional` type for optional function arguments. For example: -- -- > import Data.Optional -- > -- > greet :: Optional String -> String -- > greet (Specific name) = "Hello, " ++ name -- > greet Default = "Hello" -- -- >>> greet (Specific "John") -- "Hello, John" -- >>> greet Default -- "Hello" -- -- The `Optional` type overloads as many Haskell literals as possible so -- that you do not need to wrap values in `Specific`. For example, if you -- enable the `OverloadedStrings` extension you can use a naked string -- literal instead: -- -- >>> :set -XOverloadedStrings -- >>> greet "John" -- "Hello, John" -- -- The `Optional` type also implements `Num` and `Fractional`, so you can -- use numeric literals in place of `Optional` values: -- -- > birthday :: Optional Int -> String -- > birthday (Specific age) = "You are " ++ show age ++ " years old!" -- > birthday Default = "You are one year older!" -- -- >>> birthday 20 -- "You are 20 years old!" -- >>> birthday Default -- "You are one year older!" -- -- The `IsString`, `Num`, and `Fractional` instances are recursive, so you -- can wrap your types in a more descriptive newtype and derive `IsString`, -- `Num` or `Fractional`: -- -- > {-# LANGUAGE GeneralizedNewtypeDeriving #-} -- > -- > import Data.Optional -- > import Data.String (IsString) -- > -- > newtype Name = Name { getName :: String } deriving (IsString) -- > -- > greet :: Optional Name -> String -- > greet (Specific name) = "Hello, " ++ getName name -- > greet Default = "Hello" -- > -- > newtype Age = Age { getAge :: Int } deriving (Num) -- > -- > birthday :: Optional Age -> String -- > birthday (Specific age) = "You are " ++ show (getAge age) ++ " years old!" -- > birthday Default = "You are one year older!" -- -- ... and you would still be able to provide naked numeric or string -- literals: -- -- >>> :set -XOverloadedStrings -- >>> greet "John" -- "Hello, John" -- >>> birthday 20 -- "You are 20 years old!" -- -- You can use `empty` as a short-hand for a `Default` argument: -- -- >>> greet empty -- "Hello" -- >>> birthday empty -- "You are one year older!" -- -- You can also use `pure` as a short-hand for a `Specific` argument: -- -- >>> greet (pure "John") -- "Hello, John" -- >>> birthday (pure 20) -- "You are 20 years old!" module Data.Optional ( -- * Optional Optional(..) , defaultTo , fromOptional , optional -- * Re-exports , empty , pure ) where import Control.Applicative (Applicative(..), Alternative(..), liftA2) import Control.Monad (MonadPlus(..)) import Data.Foldable (Foldable) import Data.Traversable (Traversable) import Data.Monoid (Monoid(..)) import Data.Semigroup (Semigroup(..)) import Data.String (IsString(..)) -- | A function argument that has a `Default` value data Optional a = Default | Specific a deriving (Eq, Functor, Foldable, Traversable, Show) instance Applicative Optional where pure = Specific Specific f <*> Specific x = Specific (f x) _ <*> _ = Default instance Monad Optional where return = Specific Default >>= _ = Default Specific x >>= f = f x instance Alternative Optional where empty = Default Default <|> x = x x <|> _ = x instance MonadPlus Optional where mzero = empty mplus = (<|>) instance Semigroup a => Semigroup (Optional a) where (<>) = liftA2 (<>) instance Monoid a => Monoid (Optional a) where mempty = pure mempty #if !(MIN_VERSION_base(4,11,0)) mappend = liftA2 mappend #endif instance IsString a => IsString (Optional a) where fromString str = pure (fromString str) instance Num a => Num (Optional a) where fromInteger n = pure (fromInteger n) (+) = liftA2 (+) (*) = liftA2 (*) (-) = liftA2 (-) negate = fmap negate abs = fmap abs signum = fmap signum instance Fractional a => Fractional (Optional a) where fromRational n = pure (fromRational n) recip = fmap recip (/) = liftA2 (/) -- | The 'optional' function takes a default value, a function, and an -- 'Optional' value. If the 'Optional' value is 'Default', the function returns -- the default value. Otherwise, it applies the function to the value inside the -- 'Optional' and returns the result. optional :: b -> (a -> b) -> Optional a -> b optional n _ Default = n optional _ f (Specific x) = f x -- | The 'defaultTo' function takes a default value and an 'Optional' -- value. If the 'Optional' is 'Default', it returns the default value; -- otherwise, it returns the value contained in the 'Optional'. defaultTo :: a -> Optional a -> a defaultTo d Default = d defaultTo _ (Specific v) = v -- | Convert an 'Optional' value into an instance of 'Alternative'. fromOptional :: Alternative f => Optional a -> f a fromOptional Default = empty fromOptional (Specific x) = pure x