Difference between revisions of "Nitpicks"

From HaskellWiki
Jump to: navigation, search
(Syntax-related nitpicks: style)
(Trying to avoid the one-method-per-type-class miasma...)
 
(5 intermediate revisions by 2 users not shown)
Line 44: Line 44:
 
: See https://mail.haskell.org/pipermail/haskell-cafe/2012-August/102741.html
 
: See https://mail.haskell.org/pipermail/haskell-cafe/2012-August/102741.html
 
* Add "monad extraction" operator (I used a "!" one, because it's present in Idris ). Often you don't care in which order monad values are "extracted", and you just want to use their values in parameters to function-call or <hask>return</hask>. Compare:
 
* Add "monad extraction" operator (I used a "!" one, because it's present in Idris ). Often you don't care in which order monad values are "extracted", and you just want to use their values in parameters to function-call or <hask>return</hask>. Compare:
** "do" syntax
+
:* "do" syntax
 
<haskell>
 
<haskell>
example = do
 
 
do params <- loadParams
params <- loadParams
 
 
time <- getCurrentTime
 
time <- getCurrentTime
 
user <- getCurrentUser
 
user <- getCurrentUser
 
getExampleData params time user
 
getExampleData params time user
 
</haskell>
 
</haskell>
** monad extraction
+
:* monad extraction
 
<haskell>
 
<haskell>
example =
 
 
getExampleData !loadParams !getCurrentTime !getCurrentUser
getExampleData !loadParams !getCurrentTime !getCurrentUser
 
 
</haskell>
 
</haskell>
** Applicative lift
+
:* Applicative lift
 
<haskell>
 
<haskell>
example =
 
  +
bind3 getExampleData loadParams getCurrentTime getCurrentUser
liftA3 getExampleData loadParams getCurrentTime getCurrentUser
 
  +
where bind3 f x y z = join (liftA3 f x y z)
 
</haskell>
 
</haskell>
 
: See https://mail.haskell.org/pipermail/haskell-cafe/2014-May/114287.html
 
: See https://mail.haskell.org/pipermail/haskell-cafe/2014-May/114287.html
Line 74: Line 72:
 
* Re-naming <hask>fmap</hask> to <hask>map</hask>. This has been discussed at length; see http://stackoverflow.com/questions/6824255/whats-the-point-of-map-in-haskell-when-there-is-fmap/6824333 and https://mail.haskell.org/pipermail/haskell-prime/2006-August/thread.html
 
* Re-naming <hask>fmap</hask> to <hask>map</hask>. This has been discussed at length; see http://stackoverflow.com/questions/6824255/whats-the-point-of-map-in-haskell-when-there-is-fmap/6824333 and https://mail.haskell.org/pipermail/haskell-prime/2006-August/thread.html
 
* Cutting up <hask>Num</hask>, which is a mess of various operations one may not want to all define on some type; for example <hask>(+)</hask> makes sense for vectors in ℝ³ but <hask>(*)</hask> doesn't. Also, <hask>fromIntegral</hask> is useful for some types where the full complement of numeric operators aren't.
 
* Cutting up <hask>Num</hask>, which is a mess of various operations one may not want to all define on some type; for example <hask>(+)</hask> makes sense for vectors in ℝ³ but <hask>(*)</hask> doesn't. Also, <hask>fromIntegral</hask> is useful for some types where the full complement of numeric operators aren't.
  +
:* ...or just drop type classes altogether and use e.g. System CT [https://homepages.dcc.ufmg.br/~camarao/CT/ :] for top-level definitions by default and use annotations elsewhere, like polymorphic let-expressions [https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.187.9508 :].
 
* <hask>Data.List.nub</hask> and other "Set" operations should be restricted to <hask>Ord</hask> not <hask>Eq</hask> in order to reduce their complexity. It is very unlikely for anyone to create a datatype that can support <hask>Eq</hask> but not <hask>Ord</hask>. <hask>Data.Set</hask> in the "container" package assumes <hask>Ord</hask> as well.
 
* <hask>Data.List.nub</hask> and other "Set" operations should be restricted to <hask>Ord</hask> not <hask>Eq</hask> in order to reduce their complexity. It is very unlikely for anyone to create a datatype that can support <hask>Eq</hask> but not <hask>Ord</hask>. <hask>Data.Set</hask> in the "container" package assumes <hask>Ord</hask> as well.
 
* Partial functions like <hask>head</hask> and <hask>tail</hask> in Prelude. The problem is in their partiality.
 
* Partial functions like <hask>head</hask> and <hask>tail</hask> in Prelude. The problem is in their partiality.

Latest revision as of 22:30, 12 September 2019


This page is for people to record nitpicks about the Haskell language.

A "nitpick", in this case, is something that is annoying or could be improved, but is probably not important enough to justify the added complexity of tacking it on as an extension or breaking existing code.

In other words, if we could go back in time and fix it before it happened, we probably would, but now it would probably be too onerous.

Ideally, these nitpicks could help to inform future proposals or compatibility-breaking changes to the language. Even if they may be too onerous to change right now, it's possible that it would make sense to address them at some other time.

If the nitpick has been discussed at length, please post a link to the discussion.

Syntax-related nitpicks

example = do
   params <- loadParams
    letrequest = buildRequest params
            & fixRequest
   response <- remoteCall request
    letJust theValue = responseValueMay response
   return theValue
example = do
   params <- loadParams
   request = buildRequest params
        & fixRequest
   response <- remoteCall request
   Just theValue = responseValueMay response
   return theValue
See https://mail.haskell.org/pipermail/haskell-cafe/2012-August/102741.html
  • Add "monad extraction" operator (I used a "!" one, because it's present in Idris ). Often you don't care in which order monad values are "extracted", and you just want to use their values in parameters to function-call or return. Compare:
  • "do" syntax
do  params <- loadParams
    time <- getCurrentTime
    user <- getCurrentUser
    getExampleData params time user
  • monad extraction
getExampleData !loadParams !getCurrentTime !getCurrentUser
  • Applicative lift
bind3 getExampleData loadParams getCurrentTime getCurrentUser
where bind3 f x y z = join (liftA3 f x y z)
See https://mail.haskell.org/pipermail/haskell-cafe/2014-May/114287.html

Syntactic-sugar related nitpicks

  • It is not possible to create non-recursive bindings in do-blocks. Some syntactic sugar, say, an "assignment arrow" foo <-= modify foo which desugars to foo' (modify foo) where foo' foo = ..., would solve this problem, and can be used instead of let. The primary motivation for this is that it is currently not possible to "mutate" bindings in do-blocks, for example - let foo = modify foo would be interpreted as a recursive definition instead. So we have to invent new variable names to refer to the mutated values (suffixing (') being the most common), and since the old binding is still in scope there is no way to ensure that the old value will not be accidentally used, causing bugs. A universal non-recursive let would also solve this problem but it has its own issues, and is a much bigger change to the language. Some relevant discussion here - http://permalink.gmane.org/gmane.comp.lang.haskell.cafe/117846

Semantics-related nitpicks

Base-related nitpicks

  • ...or just drop type classes altogether and use e.g. System CT : for top-level definitions by default and use annotations elsewhere, like polymorphic let-expressions :.
  • Data.List.nub and other "Set" operations should be restricted to Ord not Eq in order to reduce their complexity. It is very unlikely for anyone to create a datatype that can support Eq but not Ord. Data.Set in the "container" package assumes Ord as well.
  • Partial functions like head and tail in Prelude. The problem is in their partiality.