optional-args (empty) → 1.0.0
raw patch · 4 files changed
+201/−0 lines, 4 filesdep +basesetup-changed
Dependencies added: base
Files
- LICENSE +24/−0
- Setup.hs +2/−0
- optional-args.cabal +26/−0
- src/Data/Optional.hs +149/−0
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ optional-args.cabal view
@@ -0,0 +1,26 @@+Name: optional-args+Version: 1.0.0+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+ Exposed-Modules: Data.Optional+ GHC-Options: -O2 -Wall+ Default-Language: Haskell2010
+ src/Data/Optional.hs view
@@ -0,0 +1,149 @@+{-# 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(..)++ -- * 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.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 Monoid a => Monoid (Optional a) where+ mempty = pure mempty++ mappend = liftA2 mappend++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 (/)