The Other Prelude
From HaskellWiki
Nmessenger (Talk  contribs) (Imported Prelude(id, const), now it compiles.) 
Uchchwhash (Talk  contribs) m (→See also) 

(15 intermediate revisions by 7 users not shown)  
Line 14:  Line 14:  
** whole English words and camelCase for functions (''e.g.'', <hask>orElse</hask> but not <hask>fmap</hask>) 
** whole English words and camelCase for functions (''e.g.'', <hask>orElse</hask> but not <hask>fmap</hask>) 

−  == The Hierarchy == 
+  == Design Philosophy == 
−  Although, not Haskell 98, hierarchical modules will definitely be in Haskell'. We take it for granted. 
+  === Taking Typeclasses Seriously === 
+  Following [[Not just Maybe]], functions should be generalized whenever possible. Of course, efficiency might be a concern but this is a fun project anyway. 

+  * <hask>concat</hask> means the same thing as <hask>join</hask>. We propose we don't use <hask>concat</hask> at all. 

+  * <hask>concatMap</hask> is just <hask>(>>=)</hask>. That is, monadic functions are preferred over the same functions with different name. 

+  
+  === The Hierarchy === 

+  
+  Although, not Haskell98, hierarchical modules are already in Haskell2010. We take it for granted. 

* <hask>TheOtherPrelude</hask>  Minimalistic module. 
* <hask>TheOtherPrelude</hask>  Minimalistic module. 

* <hask>TheOtherPrelude.Utilities</hask>  Convenient definitions. The reasoning behind its existence is that we want the Prelude to be very concise. It should not steal good names. 
* <hask>TheOtherPrelude.Utilities</hask>  Convenient definitions. The reasoning behind its existence is that we want the Prelude to be very concise. It should not steal good names. 

+  * <hask>TheOtherPrelude.Legacy</hask>  providing as much backwards compatibility as possible 

== Open Issues == 
== Open Issues == 

−  * Should <hask>Functor</hask> imply <hask>Monad</hask> or the other way around? 

* When the same function has an infix and a prefix implementation, should one of them be outside the class to enforce consistency? 
* 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 <hask>Integer</hask> instead of <hask>Int</hask>? 
+  * Should Prelude functions use <hask>Integer</hask> instead of <hask>Int</hask>? Maybe <hask>Integral n => n</hask> or <hask>Ix i => i</hask> in some cases? 
* Should <hask>String</hask> be a class rather than a type synonym? 
* Should <hask>String</hask> be a class rather than a type synonym? 

* The current proposal lacks a well thought <hask>fail</hask> mechanism. Should it be integrated into <hask>MonadZero</hask>, or have a class of his own, or remain in the <hask>Monad</hask> class? 
* The current proposal lacks a well thought <hask>fail</hask> mechanism. Should it be integrated into <hask>MonadZero</hask>, or have a class of his own, or remain in the <hask>Monad</hask> class? 

Line 30:  Line 30:  
== Reality == 
== Reality == 

−  What we have here right now is not ready to be adopted by existing projects. May be the [[class system extension proposal]] can make a difference. 
+  What we have here right now is not ready to be adopted by existing projects. The [[class system extension proposal]] might make a difference. 
== The Code == 
== The Code == 

Line 36:  Line 36:  
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. 
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, 
+  The imaginary Prelude as it stands: 
=== <hask>TheOtherPrelude.hs</hask> === 
=== <hask>TheOtherPrelude.hs</hask> === 

<haskell> 
<haskell> 

+  {# LANGUAGE NoImplicitPrelude #} 

+  
module TheOtherPrelude where 
module TheOtherPrelude where 

−  import Prelude (id, const)  hide everything 
+  import Prelude (id, const, flip, (.)) 
+   hide almost everything 

+   in fact, we could do better, by just defining them here 

+  
+   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. 

−   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. 

class Functor f where 
class Functor f where 

map :: (a > b) > f a > f b 
map :: (a > b) > f a > f b 

−  (.) :: (Functor f) => (a > b) > f a > f b 
+   definitely a bad idea, sorry Cale! 
−  (.) = map  defined outside the class as an infix synonym for map. 
+   (.) :: (Functor f) => (a > b) > f a > f b 
+   (.) = map 

−   The following has been shamelessly copied from the 

−   Functor hierarchy proposal page (see links below). 

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 
+  pure :: a > p a  value lifting 
−  (<*>) :: p (a > b) > p a > p b  lifted application 
+   actually I think we should 
+   stick to return 

+   to make do notation work 

+  (<@>) :: 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 

−   Default definition: 
+  pa >> pb = (const id) . pa <@> pb 
−  f >> g = (map (const id) f) <*> g 
+  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 = (<*>)  defined outside the class as a prefix synonym for (<*>). 
+  apply = (<@>) 
class (Applicative m) => Monad m where 
class (Applicative m) => Monad m where 

Line 74:  Line 70:  
join :: m (m a) > m a  combining levels of structure 
join :: m (m a) > m a  combining levels of structure 

−   Default definitions: 
+  ma >>= k = join (map k ma) 
−  x >>= f = join (map f x) 
+  join mma = mma >>= id 
−  join x = x >>= 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 shamelessly copy from the MonadPlus reform proposal (link below) now. 
+   We copy from the MonadPlus reform proposal (link below) now. 
 'zero' will be used when pattern matching against refutable patterns in 
 'zero' will be used when pattern matching against refutable patterns in 

 donotation as well as to provide support for monad comprehensions. 
 donotation as well as to provide support for monad comprehensions. 

−   Should satisfy 'left zero': zero >>= f = zero 
+  
class (Monad mz) => MonadZero mz where 
class (Monad mz) => MonadZero mz where 

+   Should satisfy 'left zero': zero >>= f = zero 

zero :: mz a 
zero :: mz a 

−   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) 

class (MonadZero mp) => MonadPlus mp where 
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 
(++) :: mp a > mp a > mp a 

−   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 

class (MonadZero mo) => MonadOr mo where 
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 
orElse :: mo a > mo a > mo a 

+  
+  class (Monad m) => MonadFail m where 

+  fail :: String > m a 

</haskell> 
</haskell> 

Line 109:  Line 110:  
 this is the ifthenelse proposal 
 this is the ifthenelse proposal 

 the name has been chosen to reflect the magic of Church booleans! 
 the name has been chosen to reflect the magic of Church booleans! 

−  boolean True x _ = x 
+   the order of arguments matches that of maybe and either. 
−  boolean False _ y = y 
+  boolean x _ True = x 
+  boolean _ y False = y 

</haskell> 
</haskell> 

Line 118:  Line 119:  
 ''The Other Prelude'' is an alternative, not a replacement. 
 ''The Other Prelude'' is an alternative, not a replacement. 

 So we need to hide everything from the Prelude 
 So we need to hide everything from the Prelude 

−  import Prelude () 
+  import Prelude () 
−  +   Now that we have it, 

+  {# LANGUAGE NoImplicitPrelude #} 

 This is just an example assuming there is nothing to hide 
 This is just an example assuming there is nothing to hide 

import TheOtherPrelude 
import TheOtherPrelude 

Line 125:  Line 126:  
 Hopefully, this module will contain lift,... 
 Hopefully, this module will contain lift,... 

 Standard convention is to use M.lift (instead of liftM) 
 Standard convention is to use M.lift (instead of liftM) 

−  import qualified TheOtherPrelude.Monad.Kleisli as M 
+   import qualified TheOtherPrelude.Monad.Kleisli as M 
</haskell> 
</haskell> 

Line 131:  Line 132:  
* [[Class system extension proposal]]  Makes this proposal worth reading at last 
* [[Class system extension proposal]]  Makes this proposal worth reading at last 

+  * [[Quantified contexts]]  Another important issue 

* [[Functor hierarchy proposal]]  Making <hask>Monad m</hask> imply <hask>Functor m</hask> (adopted by ''The Other Prelude''). 
* [[Functor hierarchy proposal]]  Making <hask>Monad m</hask> imply <hask>Functor m</hask> (adopted by ''The Other Prelude''). 

+  * [[FunctorApplicativeMonad Proposal]]  in essence the same proposal, perhaps showing this sentiment is more common than assumed 

* [[Ifthenelse]]  Making <hask>if</hask> a function (partially adopted by ''The Other Prelude'', we are silent on the bigger issue of sugar). 
* [[Ifthenelse]]  Making <hask>if</hask> a function (partially adopted by ''The Other Prelude'', we are silent on the bigger issue of sugar). 

* [http://software.complete.org/missingh/static/doc/ MissingH]  Functions "missing" from the Haskell Prelude/libraries. 
* [http://software.complete.org/missingh/static/doc/ MissingH]  Functions "missing" from the Haskell Prelude/libraries. 

* [[MonadPlus reform proposal]]  Clarifies ambiguities around MonadPlus laws (adopted by ''The Other Prelude'') 
* [[MonadPlus reform proposal]]  Clarifies ambiguities around MonadPlus laws (adopted by ''The Other Prelude'') 

−  * [[Mathematical prelude discussion]]  A numeric Prelude in good shape already. Will a merger be ever possible? 
+  * [[Mathematical prelude discussion]]  A [[Numeric Prelude]] in good shape already. Will a merger be ever possible? 
−  * [[Prelude extensions]] and [[Prelude function suggestions]]  Unlike ''The Other Prelude'' they ''enhance'' the Prelude. 
+  * [[Prelude extensions]] and [[List function suggestions]]  Unlike ''The Other Prelude'' they ''enhance'' the Prelude. 
−  * [http://haskell.org/hawiki/NotJustMaybe NotJustMaybe]  Instead of writing inside a specific monad (i.e. Maybe) write functions generalized on (Monad m)=> where possible. 
+  * [[Not just Maybe]]  Instead of writing inside a specific monad (i.e. Maybe) write functions generalized on (Monad m)=> where possible. 
[[Category:Proposals]] 
[[Category:Proposals]] 
Latest revision as of 22:37, 22 December 2010
Contents 
[edit] 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.
[edit] 2 Committee
This project has no committee whatsoever. Issues are discussed on the talk page.
[edit] 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., is replaced bymplus)(++)
 whole English words and camelCase for functions (e.g., but notorElse)fmap
 descriptive symbols for functions that are naturally infix (e.g.,
[edit] 4 Design Philosophy
[edit] 4.1 Taking Typeclasses Seriously
Following Not just Maybe, functions should be generalized whenever possible. Of course, efficiency might be a concern but this is a fun project anyway.
 means the same thing asconcat. We propose we don't usejoinat all.concat
 is justconcatMap. That is, monadic functions are preferred over the same functions with different name.(>>=)
[edit] 4.2 The Hierarchy
Although, not Haskell98, hierarchical modules are already in Haskell2010. We take it for granted.
  Minimalistic module.TheOtherPrelude
  Convenient definitions. The reasoning behind its existence is that we want the Prelude to be very concise. It should not steal good names.TheOtherPrelude.Utilities
  providing as much backwards compatibility as possibleTheOtherPrelude.Legacy
[edit] 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 instead ofInteger? MaybeIntorIntegral n => nin some cases?Ix i => i
 Should be a class rather than a type synonym?String
 The current proposal lacks a well thought mechanism. Should it be integrated intofail, or have a class of his own, or remain in theMonadZeroclass?Monad
[edit] 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.
[edit] 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:
[edit] 7.1 TheOtherPrelude.hs
{# LANGUAGE NoImplicitPrelude #} module TheOtherPrelude where import Prelude (id, const, flip, (.))  hide almost everything  in fact, we could do better, by just defining them here  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  definitely a bad idea, sorry Cale!  (.) :: (Functor f) => (a > b) > f a > f b  (.) = map class (Functor p) => Applicative p where  Minimal complete definition: return and (<@>). pure :: a > p a  value lifting  actually I think we should  stick to return  to make do notation work (<@>) :: 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 = (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  donotation 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 class (Monad m) => MonadFail m where fail :: String > m a
[edit] 7.2 TheOtherPrelude/Utilities.hs
module TheOtherPrelude.Utilities where import Prelude ()  hide everything  this is the ifthenelse 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
[edit] 8 How To Use
 ''The Other Prelude'' is an alternative, not a replacement.  So we need to hide everything from the Prelude import Prelude ()  Now that we have it, {# LANGUAGE NoImplicitPrelude #}  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
[edit] 9 See also
 Class system extension proposal  Makes this proposal worth reading at last
 Quantified contexts  Another important issue
 Functor hierarchy proposal  Making implyMonad m(adopted by The Other Prelude).Functor m
 FunctorApplicativeMonad Proposal  in essence the same proposal, perhaps showing this sentiment is more common than assumed
 Ifthenelse  Making a function (partially adopted by The Other Prelude, we are silent on the bigger issue of sugar).if
 MissingH  Functions "missing" from the Haskell Prelude/libraries.
 MonadPlus reform proposal  Clarifies ambiguities around MonadPlus laws (adopted by The Other Prelude)
 Mathematical prelude discussion  A Numeric Prelude in good shape already. Will a merger be ever possible?
 Prelude extensions and List function suggestions  Unlike The Other Prelude they enhance the Prelude.
 Not just Maybe  Instead of writing inside a specific monad (i.e. Maybe) write functions generalized on (Monad m)=> where possible.