Personal tools

The Other Prelude

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(oops)
(renaming <*> to <@> because ap isn't symmetric.)
Line 64: Line 64:
   
 
class (Functor p) => Applicative p where
 
class (Functor p) => Applicative p where
-- Minimal complete definition: return and (<*>).
+
-- Minimal complete definition: return and (<@>).
 
return :: a -> p a -- value lifting
 
return :: a -> p a -- value lifting
(<*>) :: p (a -> b) -> p a -> p b -- lifted application
+
(<@>) :: p (a -> b) -> p a -> p b -- lifted application
 
(>>) :: p a -> p b -> p b -- when the second is independent of the first
 
(>>) :: p a -> p b -> p b -- when the second is independent of the first
   
 
pa >> pb = map (const id) pa <*> pb
 
pa >> pb = map (const id) pa <*> pb
--map f pa = return f <*> pa -- see Class system extension proposal, below
+
--map f pa = return f <@> pa -- see Class system extension proposal, below
   
 
apply :: (Applicative p) => p (a -> b) -> p a -> p b
 
apply :: (Applicative p) => p (a -> b) -> p a -> p b
apply = (<*>)
+
apply = (<@>)
   
 
class (Applicative m) => Monad m where
 
class (Applicative m) => Monad m where
Line 82: Line 82:
 
ma >>= k = join (map k ma)
 
ma >>= k = join (map k ma)
 
join mma = mma >>= id
 
join mma = mma >>= id
--mf <*> ma = mf >>= flip map ma -- see Class system extension proposal, below
+
--mf <@> ma = mf >>= flip map ma -- see Class system extension proposal, below
 
--ma >> mb = ma >>= const mb
 
--ma >> mb = ma >>= const mb
 
--map f ma = ma >>= return . f -- this depends on (.), which is map! Be careful.
 
--map f ma = ma >>= return . f -- this depends on (.), which is map! Be careful.

Revision as of 23:38, 25 November 2008

Contents

1 Call For Contribution

This fun project, called The Other Prelude, is a creative reconstruction of the standard Prelude. By disregarding history and compatibility, we get a clean sheet.

2 Committee

This project has no committee whatsoever. Issues are discussed on the talk page.

3 Naming Conventions

  • Function names should be easy for beginners to consume.
  • Specifically, The Other Prelude naming convention is to use
    • descriptive symbols for functions that are naturally infix (e.g.,
      mplus
      is replaced by
      (++)
      )
    • whole English words and camelCase for functions (e.g.,
      orElse
      but not
      fmap
      )

4 Design Philosophy

4.1 Taking Typeclasses Seriously

Following NotJustMaybe (unfortunately I can't find the page), functions should be generalized whenever possible. Of course, efficiency might be a concern but this is a fun project anyway.

  • concat
    means the same thing as
    join
    . We propose we don't use
    concat
    at all.
  • concatMap
    is just
    (>>=)
    . That is, monadic functions are preferred over the same functions with different name.

4.2 The Hierarchy

Although, not Haskell 98, hierarchical modules will definitely be in Haskell'. We take it for granted.

  • TheOtherPrelude
    - Minimalistic module.
  • TheOtherPrelude.Utilities
    - Convenient definitions. The reasoning behind its existence is that we want the Prelude to be very concise. It should not steal good names.

5 Open Issues

  • When the same function has an infix and a prefix implementation, should one of them be outside the class to enforce consistency?
  • Should Prelude functions use
    Integer
    instead of
    Int
    ? Maybe
    Integral n => n
    or
    Ix i => i
    in some cases?
  • Should
    String
    be a class rather than a type synonym?
  • The current proposal lacks a well thought
    fail
    mechanism. Should it be integrated into
    MonadZero
    , or have a class of his own, or remain in the
    Monad
    class?

6 Reality

What we have here right now is not ready to be adopted by existing projects. The class system extension proposal might make a difference.

7 The Code

Currently, the code is in Wiki form. If people do agree that the collaborative decisions begot something pretty, we'll have a group of files in darcs.haskell.org some time.

The imaginary Prelude as it stands:

7.1
TheOtherPrelude.hs

module TheOtherPrelude where
 
import Prelude (id, const, flip) -- hide almost everything
 
-- The idea is to rename 'fmap'.
-- Both map :: (a -> b) -> [a] -> [b]           (in [])
-- and  (.) :: (a -> b) -> (e -> a) -> (e -> b) (in (->) e)
-- are good names, and are intuitively prefix and infix respectively.
-- 'map' is aliased as (.) below.
 
class Functor f where
  map :: (a -> b) -> f a -> f b
 
(.) :: (Functor f) => (a -> b) -> f a -> f b
(.) = map
 
class (Functor p) => Applicative p where
  -- Minimal complete definition: return and (<@>).
  return :: a -> p a                 -- value lifting
  (<@>)  :: p (a -> b) -> p a -> p b -- lifted application
  (>>)   :: p a -> p b -> p b        -- when the second is independent of the first
 
  pa >> pb = map (const id) pa <*> pb
--map f pa = return f <@> pa -- see Class system extension proposal, below
 
apply :: (Applicative p) => p (a -> b) -> p a -> p b
apply = (<@>)
 
class (Applicative m) => Monad m where
  -- Minimal complete definition: one of join or (>>=).
  (>>=) :: m a -> (a -> m b) -> m b -- bind
  join  :: m (m a) -> m a           -- combining levels of structure
 
  ma >>= k  = join (map k ma)
  join mma  = mma >>= id
--mf <@> ma = mf >>= flip map ma -- see Class system extension proposal, below
--ma >> mb  = ma >>= const mb
--map f ma  = ma >>= return . f -- this depends on (.), which is map!  Be careful.
 
-- We copy from the MonadPlus reform proposal (link below) now.
-- 'zero' will be used when pattern matching against refutable patterns in
-- do-notation as well as to provide support for monad comprehensions.
 
class (Monad mz) => MonadZero mz where
  -- Should satisfy 'left zero': zero >>= f = zero
  zero :: mz a
 
class (MonadZero mp) => MonadPlus mp where
  -- Should satisfy 'monoid':
  --   zero ++ b = b;  b ++ zero = b
  --   (a ++ b) ++ c = a ++ (b ++ c)
  -- and 'left distribution':
  --   (a ++ b) >>= f = (a >>= f) ++ (b >>= f)
  (++) :: mp a -> mp a -> mp a
 
class (MonadZero mo) => MonadOr mo where
  -- Should satisfy 'monoid':
  --   zero `orElse` b = b;  b `orElse` zero = b
  --   (a `orElse` b) `orElse` c = a `orElse` (b `orElse` c)
  -- and 'left catch':
  --   (return a) `orElse` b = a
  orElse :: mo a -> mo a -> mo a

7.2
TheOtherPrelude/Utilities.hs

module TheOtherPrelude.Utilities where
import Prelude () -- hide everything
 
-- this is the if-then-else proposal
-- the name has been chosen to reflect the magic of Church booleans!
-- the order of arguments matches that of maybe and either.
boolean x _ True = x
boolean _ y False = y

8 How To Use

-- ''The Other Prelude'' is an alternative, not a replacement.
-- So we need to hide everything from the Prelude
import Prelude ()
 
-- This is just an example assuming there is nothing to hide
import TheOtherPrelude
 
-- Hopefully, this module will contain lift,...
-- Standard convention is to use M.lift (instead of liftM)
import qualified TheOtherPrelude.Monad.Kleisli as M

9 See also