Code Monkey home page Code Monkey logo

purescript-control's Introduction

PureScript

A small strongly typed programming language with expressive types that compiles to JavaScript, written in and inspired by Haskell.

Hackage Build Status

Language info

Resources

Help!

Community Spaces

The following spaces are governed by the PureScript Community Code of Conduct. The majority of PureScript users use these spaces to discuss and collaborate on PureScript-related topics:

Unaffiliated Spaces

Some PureScript users also collaborate in the below spaces. These do not fall under the code of conduct linked above. They may have no code of conduct or one very different than the one linked above.

purescript-control's People

Contributors

garyb avatar hdgarrood avatar jamiewohletz avatar joneshf avatar jordanmartinez avatar kl0tl avatar liamgoodacre avatar masaeedu avatar matthewleon avatar milesfrain avatar paf31 avatar pseudonom avatar spicydonuts avatar thimoteus avatar thomashoneyman avatar zudov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

purescript-control's Issues

Unknown module Data.Functor Control.Category, Data.Unit, Prelude

So I've been using Prelude and such for some time and now after installing Purescript-Rx which I suppose depends on Purescript-Control I get these errors. What baffles me most is that I do not understand why it cant see Prelude because minutes ago I successfully imported it with other libs.

Errors:

[1/4 UnknownModule] bower_components\purescript-control\src\Control\Alt.purs:6:1

  6  import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>))
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  Unknown module Data.Functor

[2/4 UnknownModule] bower_components\purescript-control\src\Control\Extend.purs:9:1

      v
   9  import Control.Category (id)
  10
      ^

  Unknown module Control.Category

[3/4 UnknownModule] bower_components\purescript-control\src\Control\Lazy.purs:3:1

     v
  3  import Data.Unit (Unit)
  4
     ^

  Unknown module Data.Unit

My bower:

{
  "name": "front-ps",
  "version": "1.0.0",
  "moduleType": [
    "node"
  ],
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "output"
  ],
  "dependencies": {
    "purescript-console": "^0.1.1",
    "purescript-eff": "^1.0.0-rc.1",
    "purescript-prelude": "^1.0.0-rc.3",
    "purescript-functions": "^1.0.0-rc.1",
    "purescript-maybe": "^1.0.0-rc.2",
    "purescript-rx": "^0.8.2"
  },
  "resolutions": {
    "purescript-prelude": "^1.0.0-rc.3",
    "purescript-maybe": "^1.0.0-rc.2",
    "purescript-monoid": "^1.0.0-rc.2",
    "purescript-control": "^1.0.0-rc.1",
    "purescript-invariant": "^1.0.0-rc.1",
    "purescript-console": "^1.0.0-rc.1",
    "purescript-eff": "^1.0.0-rc.1",
    "purescript-functions": "^1.0.0-rc.1"
  }
}

Annihilation law of alternative has incorrect order?

-- | - Annihilation: `empty <*> f = empty`
class (Applicative f, Plus f) <= Alternative f

(<*>) :: f (a -> b) -> f a -> f b

As I understand on left side of <*> we should have container containing function and on the right side a container containing value.
From this, looks like the law is incorrect and should be like this: `

f <*> empty = empty

-- types of each part in this case
f <*> empty :: Alternative f' => f' a
f           :: Alternative f' => f' (a -> a)
      empty :: Alternative f' => f' a
  <*>       :: Alternative f' => f' (a -> b) -> f' a -> f' b

provide filter for Alternative and Monad?

We can define filter which work on any Alternative and Monad

filter ::  m a. Alternative m => Monad m => (a -> Boolean) -> m a -> m a
filter f m = m >>= \x -> if f x then pure x else empty

I think this repo is best place for it, but i might be wrong.

Draw a MonadZero out of MonadPlus?

See also: purescript-contrib/purescript-quickcheck-laws#7

I think that the situation is this:

  • Suppose we have some type A :: * -> * with Alternative and Monad instances.
  • For such a type to have a MonadPlus instance, it currently needs to satisfy:
    • Distributivity: (x <|> y) >>= f == (x >>= f) <|> (y >>= f)
    • Annihilation: empty >>= f = empty
  • There is at least one such type A for which guard is useful but which does not satisfy distributivity; Maybe.
  • We want all our instances to be law-abiding, but we also want to be able to use functions like guard with types like Maybe.
  • guard should include a constraint to ensure that the type satisifies annihilation.

Therefore, I propose that we add a new empty class as follows:

class (Monad m, Alternative m) <= MonadZero m

with the annihilation law. Then, MonadPlus would only have a MonadZero constraint, and the distributivity law. Finally, guard should have a MonadZero constraint.

Then Maybe could have MonadZero but not MonadPlus, and we could use guard with it.

Deprecate MonadZero

I proposed MonadZero originally, so it feels somehow appropriate that I’m going to be the one to argue for its demise.

Anyway, as noted in #51, the MonadZero annihilation law empty >>= f = empty is automatically satisfied for any law-abiding monad, due to parametricity: while evaluating empty >>= f, the function f can’t ever be called, since that would require empty to produce a value, which means that empty >>= f must be the same as empty >>= pure, which by the monad laws is just empty.

As far as I’m aware, the only place we’re using MonadZero is in the definition of guard. However, I’d argue that the Alternative annihilation law empty <*> f = empty already gives us enough to ensure that guard behaves sensibly. Haskell seems to agree, with its guard only requiring Alternative.

(Note: The Alternative annihilation law isn’t redundant: for a type which isn’t a monad, the effects of the second argument of <*> could be performed before the first).

Therefore, I propose we do the following:

  • Add a deprecation notice to the MonadZero class
  • Change guard to only require Alternative
  • Change MonadPlus to have Monad and Alternative superclasses instead of MonadZero
  • In a subsequent breaking release, remove MonadZero.

Proposal: Make <|> right associative

Is there a practical reason for <|> being left associative? In general, it's a control structure, where right-associativity is desirable (eg, what if if/then/else was left associative? It just doesn't make sense). For example, in all the canonical instance for parsers or Maybe, or Lists, left associativity leads to terrible evaluation characteristics and almost always requires more work than right-associativity. I always have to define a new local alias when writing parsers because it's a significant improvement.

MonadZero and MonadPlus seem redundant?

Given the laws of Monad that state apply = ap as well as the laws of Alternative that state
empty <*> f = empty, we can practically derive the MonadZero law empty >>= f = empty.
Thus, it seems to me that we do not need to specify this law in addition to the laws already present.

Furthermore, MonadPlus has the requirement that >>= distribute over <|>. Though as it extends Alternative which already requires distribution of <*> over <|> and again, since <*> = ap we already get that property. Am I missing something here?

Definition '(<|>)' conflicts with import 'Prelude.(<|>)'

I used grunt-init-purescript to make a new project following the instructions from the book . Initial project compilation fails because (<|>) is defined in Prelude and in Control.Alt.

Running "pscMake:lib" (pscMake) task
>> Make failed:
>> Error in module Control.Alt
>> Definition '(<|>)' conflicts with import 'Prelude.(<|>)'
Definition '(<|>)' conflicts with import 'Prelude.(<|>)'

Use fundeps for an intermediate representation in `defer`

One issue with this typeclass I frequently come up against is that it almost always requires extra layers of thunks. For example, the Lazy, List, and Cofree data types all require an extra thunk which is immediately forced inside another suspension. This makes me hesitate to use it for something like a general purpose lazy fold because it's always going to carry a lot more overhead than necessary. Maybe we could have the class indexed by an intermediate representation?

class Lazy rep a | a -> rep where
  defer :: (Unit -> rep) -> a

instance lazyLazy :: Lazy a (Z.Lazy a) where
  defer = Z.defer

instance lazyCofree :: Lazy (Tuple a (Cofree f a)) (Cofree f a) where
  defer = deferCofree

instance lazyList :: Lazy (Step a) (List a) where
  defer = List <<< Z.defer

Monad as Category Instance

Is there any way to make monads an instance of category so that normal composition can be used in place of (<=<)? (I'm not very familiar with the type system features available in purescript.)

type MonArr m a b = MonArr (a -> m b)
instance catMon :: (Monad m) => Category (MonArr m) where
  id x = return x
  (<<<) f g x = g x >>= f

That doesn't seem to work for lack of type synonym instances (which can be worked around with an ugly data declaration).

purescript-control#^3.0.0 vs purescript-control#^4.0.0

Unable to find a suitable version for purescript-control, please choose one by typing one of the numbers below: 1) purescript-control#^3.0.0 which resolved to 3.3.1 and is required by purescript-monoid#3.3.0 2) purescript-control#^4.0.0 which resolved to 4.1.0 and is required by purescript-either#4.1.1, purescript-foldable-traversable#4.1.1, purescript-identity#4.1.0, purescript-lazy#4.0.0, purescript-lists#5.4.0, purescript-maybe#4.0.1, purescript-nonempty#5.0.0, purescript-tuples#5.1.0

Add MonadOr?

it would be nice to add MonadOr typeclass:

-- | The `MonadOr` type class has no members of its own but extends
-- | `MonadZero` with an additional law:
-- |
-- | - Left catch: `(return a) <|> b = return a`
class MonadZero m <= MonadOr m

For example IO could be an instance of MonadOr.

But it adding MonadOr will introduce other issue: some structures could conform to MonadOr and MonadPlus and adding empty MonadOr will make it impossible to express that. See example from MonadPlus reform proposal#Instances of both

instance MonadPlus Maybe where
   mplus (Just a) Nothing = Just a
   mplus Nothing (Just a) = Just a
   mplus _ _ = Nothing
 
instance MonadOr Maybe where
  -- this is same as definition in Alternative
   morelse (Just a) _ = Just a
   morelse _ b = b


instance MonadOr [] where
   morelse [] b = b
   morelse a b = a
instance MonadPlus [] where
  -- this is same as definition in Alternative
   mplus  = (++)

If we add MonadOr it should have function with different name then <|>, haskell proposal uses morelse. but except this, we should also add a function to MonadPlus too, as pointed above some structures supports both (Maybe or List).

Related discussion in Fantasy Land

laws for Lazy

Can we have documented laws for the Lazy typeclass?

Remove deprecated MonadZero instance (v0.15.0 PS)

When we make the next round of breaking changes (e.g. v0.15.0 of PureScript), this is a reminder to remove the MonadZero instance for Array. Relates to #66, which censors user-defined warnings due to the MonadZero instance. The build command should be updated to fail on any warning once we've removed the instance.

The distributivity law for Alternative rules out effectful instances

Alternative has this distributivity law:

  • (f <|> g) <*> x == (f <*> x) <|> (g <*> x)

However, this law rules out a few instances, most notably "effectful" ones like Effect or Aff. For example:

f :: Aff (Unit -> Unit)
f = pure identity

g :: Aff (Unit -> Unit)
g = pure identity

x :: Aff Unit
x = log "hi" *> empty

for which (f <|> g) <*> x will log "hi" once, whereas (f <*> x) <|> (g <*> x) will log "hi" twice.

Note that Effect has no Alt instance right now (and therefore no Plus or Alternative either), whereas Aff does have all of those instances.

I think it would be good to decide whether we want to keep this law and say that the problem lies with Aff's instance, or condone the Aff instance by dropping the distributivity law from the Alternative class.

It would be useful to see a concrete example of a case where the distributivity law is useful for ensuring that something behaves sensibly, because I'm not aware of any (and I think Aff's instance is used quite widely in practice, and I'm not aware of this having had any real consequences).

If we did drop the Alternative distributivity law, we'd be left with just the annihilation law, empty <*> f = empty. I think this makes sense as a class: I'd argue it gives you exactly what you need to write a sensible version of guard, since the annihilation law ensures that subsequent effects after a failed guard are nullified, and you need pure from Applicative and empty from Plus (see also #62).

Include a class for `hoist`?

There's an MFunctor class in Control.Monad.Morph which is something like what I had in mind:

class MFunctor t where
  hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

But that imposes a monad constraint. I was thinking more like:

class Functor1 t where
  hoist :: (f ~> g) -> t f ~> t g

With the usual laws:

hoist (f ∘ g) = hoist f ∘ hoist g
hoist id = id

We have quite a few types with hoist operations when you get into free, yoneda, coroutines, etc.

$> breaks operator symmetry

g    $    x -- function over value
g   <$>   f -- function over Functor
g x <$    f --    value over Functor
-- flipped
  x  #  g   --    value over function
  f <#> g   --  Functor over function
  f  $> g x --  Functor over value

I feel strongly $> should be #>. Am I missing something?

Add (<$$>)

How about adding

(<$$>) = (<$>) <<< (<$>)

to Data.Functor ?

I find myself often doing map f <$> ..., a shortcut for that might be nice.

Dependencies and default implementations

Moving zipWithA into Control.Applicative from Control.Monad is a good idea, but it causes an issue.

Since we can't do default implementations in typeclasses yet we have <* and *> in Control.Applicative rather than being in the typeclass and forcing everyone to implement these as well. A similar thing happens in Data.Foldable and Data.Traversable also since we could give a default implementation of each of the other functions in terms of just one.

Now, this causes an issue. Control.Applicative defines zipWithA which requires sequence which is imported from Data.Traversable which imports Data.Foldable for its constraints which imports Control.Applicative for constraints on some functions: traverse_, for_, and sequence_..

So, we can either shuffle the definitions around, e.g. put zipWithA in Data.Traversable or something. We can move <* and *> into the typeclass and force everyone to implement these as well (the implementations that are there are fine, just would have to copy paste it everywhere 👎 ). Or we can try to get default implementations working.

Thoughts or other ideas?

Consider updating misleading Alt documentation

The Alt documentation says:

The Alt type class identifies an associative operation on a type constructor. It is similar to Semigroup, except that it applies to types of kind * -> *, like Array or List, rather than concrete types like String or Number.

I think this is misleading because my understanding of the phrase "concrete type" is that it refers to a specific, named type, as opposed to a type variable. So I would say that Array, List, String, and Number are all concrete. The important point here is just to distinguish types of kind Type with types of kind Type -> Type, so I'd suggest just saying that, and avoiding the word "concrete".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.