Giter Site home page Giter Site logo

purescript-profunctor-lenses's Introduction

Profunctor Lenses

CI Release Pursuit Maintainer: garyb

Pure profunctor lenses: a mechanism for updating, viewing, and setting values within nested data structures.

Learn more about profunctor lenses with:

Installation

Install profunctor-lenses with Spago:

spago install profunctor-lenses

Quick start

> structure = Tuple (Tuple (Tuple "hi!" 3) 2) 1

> import Data.Lens
> _leftmost = _1 <<< _1 <<< _1

> view _leftmost structure
"hi!"

> set _leftmost "Bye!" structure
(Tuple (Tuple (Tuple "Bye!" 3) 2) 1)

> over _leftmost String.toUpper structure
(Tuple (Tuple (Tuple "HI!" 3) 2) 1)

You can try out the examples in the REPL by running:

spago -x examples.dhall repl

Documentation

profunctor-lenses documentation is stored in a few places:

  1. Module documentation is published on Pursuit.
  2. Usage examples can be found in the test suite and examples directory.
  3. Practical Profunctor Optics & Lenses in PureScript, a practical introduction to profunctor optics in PureScript
  4. Lenses for the Mere Mortal, a book about lenses in PureScript

If you get stuck, there are several ways to get help:

Contributing

You can contribute to profunctor-lenses in several ways:

  1. If you encounter a problem or have a question, please open an issue. We'll do our best to work with you to resolve or answer it.

  2. If you would like to contribute code, tests, or documentation, please read the contributor guide. It's a short, helpful introduction to contributing to this library, including development instructions.

  3. If you have written a library, tutorial, guide, or other resource based on this package, please share it on the PureScript Discourse! Writing libraries and learning resources are a great way to help this library succeed.

purescript-profunctor-lenses's People

Contributors

cscalfani avatar dwhitney avatar garyb avatar joneshf avatar jonsterling avatar jordanmartinez avatar justinwoo avatar kl0tl avatar kritzcreek avatar liamgoodacre avatar marick avatar maxdeviant avatar natefaubion avatar neppord avatar paf31 avatar pbrant avatar reactormonk avatar risto-stevcev avatar roxxik avatar rufflewind avatar sigma-andex avatar simonyangme avatar sjoerdvisscher avatar syaiful6 avatar th-awake avatar themoritz avatar thomashoneyman avatar tslawler avatar xertrov avatar zrho 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  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

purescript-profunctor-lenses's Issues

Remove Index constraint from At?

I have no idea about the theoretical foundations, but is the Index constraint on all At instances really necessary? It isn't used anywhere in the At instances in profunctor-lenses at least.

Extract `Tagged a b`?

Tagged a b lives in here, but it's really useful a thing—like Const a b useful. Would you be up for pulling it out and depending on it externally?

Also, there are a ton of useful instances missing from it. Whether it stays here or not, would you be up for a PR adding those instances?

Tagged is Closed

In haskell

instance Closed Tagged where
    closed (Tagged b) = Tagged (const b)

EDIT that will make Grate usable with review.

Remove (++~) and (++=)

Since the (++) alias of append was also removed from prelude, having these in profunctor-lenses is rather odd, IMO.

traverseOf_

Not sure if intended, but traverseOf_ is not exported from Data.Lens.Fold, but sequenceOf_ and itraverseOf_ are. This seems weird to me.

Getters don't compose?

Oh no!

foo :: Getter' X Y
bar :: Getter' Y Z
fooBar :: Getter' X Z
fooBar = foo <<< bar
[1/1 TypesDoNotUnify] src/Main.purs:19:18
  19  fooBar = foo <<< bar
                       ^^^

  Could not match type
    Z

  with type
    Y

Because Getter uses Forget t and not a constraint, it can't swap out the t when composing.

Constructing a traversal where setting requires information about the current value

I've been trying to come up with a convenient lens-based way for dealing with These. I have an Iso, and Prisms for This, Both, That, but what would be most useful is something that allows getting/setting the "left" or "right" of a These, however I have no idea how to do it. Maybe it's not a law abiding construction?

The idea being, I could use _TheseLeft (or something) to:

  • read This a
  • read Both a _
  • set This a
  • update Both a _ while setting
  • take a That b and produce a Both a b while setting

I did something a little similar in the past, but that method, apart from seeming a bit dodgy in the first place, doesn't seem to translate to profunctor lenses.

Anyone out there have any ideas? @ekmett perhaps? 😄

Any interest in a ^?! function?

This can be quite handy (although unsafe)

import Data.Monoid.Endo
import Partial.Unsafe

unsafeViewPrism :: forall s t a b. s -> Partial => Fold (Endo a) s t a b -> a
unsafeViewPrism s l = foldrOf l const (unsafeCrashWith "^?! empty fold") s

infixl 8 unsafeViewPrism as ^?!

Move to contrib?

Would you consider moving this to contrib? We'll trash photons and just use this if it's somewhere where multiple maintainers can contribute/admin it.

Generalize Wander

Obviously, we need a good story for traversals. Currenty, there is the Wander type class, that allows to
lift a traversable functor into the profunctor. While this looks quite neat and similar to Choice and Strong, I think it is a bit restrictive: Sometimes, you have a traversal that only works for fixed types, e.g. with monomorphic containers. I would propose generalizing Wander to the following (admittedly quite ugly) type:

class (Strong p, Choice p) <= Wander p where
  wander
    :: forall s t a b. (forall f. (Applicative f) => (a -> f b) -> s -> f t)
    -> p a b -> p s t

Here, wander is the inverse to traverseOf. The original function can be recovered by applying traverse from Data.Traversable as the first argument. Function and Star f for Applicatives f
can be generalized to this new definition:

instance wanderFunction :: Wander Function where
  wander t p = runIdentity <<< t (Identity <<< p)

instance wanderStar :: (Applicative f) => Wander (Star f) where
  wander t = Star <<< t <<< runStar

What do you think?

IndexedLens

Add IndexedLenses

I just now had a need for IndexedLenses and haven't found any, so i played a little around and i found a solution that typechecks, not sure if this is correct, i'll send a PR soon

Strange error with Strong/Forget

Hello,
I'm using profunctor-lenses v 6.2.0 with purescript 0.13.6.
I'm getting the following error:

Error found:
in module Gargantext.Components.Nodes.Annuaire.User.Contacts
at src/Gargantext/Components/Nodes/Annuaire/User/Contacts.purs:149:22 - 149:72 (line 149, column 22 - line 149, column 72)

  Could not match constrained type

    Strong p0 => p0 String String -> p0 HyperdataUser HyperdataUser

  with type

    Forget String String t1 -> Forget String HyperdataUser t2


while trying to match type Strong p0 => p0 String String -> p0 HyperdataUser HyperdataUser
  with type Forget String String t1 -> Forget String HyperdataUser t2
while checking that expression (hooksComponent "G.C.N.A.U.C.contactInfoItem") cpt
  has type Component
             ( hyperdata :: HyperdataUser
             , lens :: forall p. Strong p => ... -> ...
             , onUpdateHyperdata :: HyperdataUser -> Effect Unit
             )
in value declaration contactInfoItemCpt

where p0 is a rigid type variable
        bound at (line 52, column 21 - line 52, column 58)
      t1 is an unknown type
      t2 is an unknown type

for the following code:
https://gitlab.iscpif.fr/gargantext/purescript-gargantext/blob/dev-user-page-lens-test/src/Gargantext/Components/Nodes/Annuaire/User/Contacts.purs#L137-154
The lens are defined here:
https://gitlab.iscpif.fr/gargantext/purescript-gargantext/blob/dev-user-page-lens-test/src/Gargantext/Components/Nodes/Annuaire/User/Contacts/Types.purs#L210-228

What is funnier, when I don't specify the types:

contactInfoItem :: Record ContactInfoItemProps -> R.Element
contactInfoItemCpt :: R.Component ContactInfoItemProps

the code compiles fine. However, it will fail at compiling when I use both the view and set functions (set is currently commented out here: https://gitlab.iscpif.fr/gargantext/purescript-gargantext/blob/dev-user-page-lens-test/src/Gargantext/Components/Nodes/Annuaire/User/Contacts.purs#L179-180) The error is then:

Error found:
in module Gargantext.Components.Nodes.Annuaire.User.Contacts
at src/Gargantext/Components/Nodes/Annuaire/User/Contacts.purs:153:27 - 153:31 (line 153, column 27 - line 153, column 31)

  Could not match type

    Function

  with type

    Forget t0


while trying to match type Function t4
  with type Forget t0 t0
while checking that expression lens
  has type Forget t0 t0 t1 -> Forget t0 t2 t3
in value declaration contactInfoItemCpt

I tried to debug this somehow and created simple code with view and set and created a stub func which is somewhat similar to contactInfoItemCpt from above:
https://gitlab.iscpif.fr/gargantext/purescript-gargantext/blob/dev-user-page-lens-test/src/LensTest.purs
The function func can be called like this:

func defaultT $ _s <<< _last

This works fine however and I'm really lost here.

Any help appreciated :)

Build Error: Unknown type class RowCons

I tried installing and building purescript-thermite and I got the following error that seems to originate in this package.

I've got purescript-profunctor-lenses#3.2.0 installed with bower and when I run pulp-build or pulp-psci I get this output (or similar).

$ pulp build
* Building project in c:\Dev\ps-report-view
Error 1 of 3:

  in module Data.Lens.Record
  at bower_components\purescript-profunctor-lenses\src\Data\Lens\Record.purs line 26, column 1 - line 32, column 7

    Unknown type class RowCons


  See https://github.com/purescript/documentation/blob/master/errors/UnknownName.md for more information,
  or to contribute content related to this error.

Error 2 of 3:

  in module Data.Lens.Record
  at bower_components\purescript-profunctor-lenses\src\Data\Lens\Record.purs line 35, column 1 - line 43, column 15

    Unknown type class RowCons


  See https://github.com/purescript/documentation/blob/master/errors/UnknownName.md for more information,
  or to contribute content related to this error.

Error 3 of 3:

  in module Data.Lens.Record
  at bower_components\purescript-profunctor-lenses\src\Data\Lens\Record.purs line 57, column 1 - line 63, column 38

    Unknown type class RowCons


  See https://github.com/purescript/documentation/blob/master/errors/UnknownName.md for more information,
  or to contribute content related to this error.

... more output snipped.

This is the version of pulp I'm running.

$ pulp --version
Pulp version 11.0.0
purs version 0.11.1 using c:\Users\gerard.paapu\AppData\Roaming\npm\purs.CMD

Compiler error with lens inside record

Any way to fix it?

type LensWrapper a b = {lens :: LensP a b}
foo :: forall a b. LensWrapper (Tuple a b) a
foo = {lens : _1}
y = (Tuple 1 2) # foo.lens .~ 10
Error found:
in module Main
at Main.purs line 115, column 5 - line 123, column 1

  Could not match constrained type

    (Strong _5) => _5 _6 _6 -> _5 (Tuple _6 _7) (Tuple _6 _7)

  with type

    (_0 -> _1) -> _2 -> _3


while trying to match type (Strong _5) => _5 _6 _6 -> _5 (Tuple _6 _7) (Tuple _6 _7)
  with type (_0 -> _1) -> _2 -> _3
while checking that expression foo
  has type { lens :: (_0 -> _1) -> _2 -> _3
           | _4
           }
while checking type of property accessor foo."lens"
in value declaration y

where _1 is an unknown type
      _0 is an unknown type
      _3 is an unknown type
      _2 is an unknown type
      _4 is an unknown type
      _7 is an unknown type
      _6 is an unknown type
      _5 is an unknown type

See https://github.com/purescript/purescript/wiki/Error-Code-ConstrainedTypeUnified for more information,
or to contribute content related to this error.

[Grate Module] Should collectOf be defined as

so i played with Grate and Distributive. It look like collectOf should be defined like this:

collectOf :: forall f s t a b. Functor f => Optic (Costar f) s t a (f a) -> (b -> s) -> f b -> t
collectOf g f = zipFWithOf g id <<< map f

so i can do collectOf cotraversed, in psci it yield type:

:t collectOf cotraversed
forall t1 t5 t7 t8. Functor t5 => Distributive t8 => (t1 -> t8 t7) -> t5 t1 -> t8 (t5 t7)

which what i want. But if i apply the current implementation to cotraversed it will yied:

:t collectOf cotraversed
forall t5 t6 t7 t8. Distributive t8 => Distributive t5 => (t7 -> t5 t6) -> t8 t7 -> t5 (t8 t6)

which i believe not what we want. Notice the Distributive constraint appear both in input and output.

Add Plated

In Haskell there is a concept of Plated where you can traverse recursive data structures structures.

It would be nice to have this in purescript.

I would love to help implement this, but I'm totally new to lenses and would need a mentor or a pair partner.

Costrong too magical? Crash in the JS layer when using it.

I've been digging into this (great!) repo and trying to create accumulating getters, meaning getters that can "pause" at a certain point of the lens, take a value, and persist it down to the final getter.

Rolling one by hand is pretty easy for a specific scenario, but coming up with a generic way to do this seems impossible. Nonetheless, the signature of Costar makes it seem like it's possible, as Costar can theoretically be used to "upgrade" a vanilla optic to an optic that takes a tuple (as I do below). However, it crashes with an odd message. The only crash I've ever seen in purescript before is maximum recursion depth (aka bottom), but this seems like a different beast...

I can also write this up in the purescript-profunctor library if the issue lies more there than here. Curious to hear everyone's thoughts.


Environment

  • PureScript 0.13.8
  • purescript-profunctor-lenses 6.3.0

Current behavior

This compiles fine but crashes when run:

module Main where

import Prelude
import Data.Lens (Iso, _1, _2, iso)
import Data.Profunctor (class Profunctor)
import Data.Profunctor.Costrong (class Costrong, unfirst, unsecond)
import Data.Profunctor.Strong (class Strong, first)
import Data.Tuple (Tuple(..), fst, snd)
import Effect (Effect)
import Effect.Console (log)
import Data.Identity (Identity(..))
import Data.Newtype (class Newtype, unwrap)
import Data.Profunctor.Costar (Costar(..))

newtype Forget' r a b
  = Forget' (a -> r)

derive instance newtypeForget' :: Newtype (Forget' r a b) _

instance profunctorForget' :: Profunctor (Forget' r) where
  dimap f _ (Forget' z) = Forget' (z <<< f)

instance strongForget' :: Strong (Forget' r) where
  first (Forget' z) = Forget' (z <<< fst)
  second (Forget' z) = Forget' (z <<< snd)

instance costrongForget' :: Costrong (Forget' r) where
  unfirst (Forget' z) = Forget' $ ((unwrap <<< unfirst <<< Costar) (\(Identity t@(Tuple x y)) -> Tuple (z t) y)) <<< Identity
  unsecond (Forget' z) = Forget' $ ((unwrap <<< unsecond <<< Costar) (\(Identity t@(Tuple x y)) -> Tuple x (z t))) <<< Identity

-- adds pathway for c to flow through in snd
firstAlley :: forall r s t a b c. (Forget' r a b -> Forget' r s t) -> Forget' r (Tuple a c) (Tuple b c) -> Forget' r (Tuple s c) (Tuple t c)
firstAlley o = first <<< o <<< unfirst

-- adds pathway for c to flow through in fst
secondAlley :: forall r s t a b c. (Forget' r a b -> Forget' r s t) -> Forget' r (Tuple a c) (Tuple b c) -> Forget' r (Tuple s c) (Tuple t c)
secondAlley o = first <<< o <<< unfirst

-- _1 with and arbitrary `c` flowing through snd
_1' ::  r a b c d. Forget' r (Tuple a c) (Tuple b c)  Forget' r (Tuple (Tuple a d) c) (Tuple (Tuple b d) c)
_1' = firstAlley _1

-- _2 with and arbitrary `c` flowing through snd
_2' ::  r a b c d. Forget' r (Tuple a c) (Tuple b c)  Forget' r (Tuple (Tuple d a) c) (Tuple (Tuple d b) c)
_2' = firstAlley _2

-- duplicates a value, pegging it as snd in a tuple
pegAtSecond :: forall a b. Iso a b (Tuple a a) (Tuple b a)
pegAtSecond = iso (\i -> Tuple i i) (\(Tuple f s) -> f)

main :: Effect Unit
main =
  log
    ( show
        ( ( unwrap
              ( (_2 <<< pegAtSecond <<< _2' <<< _2') -- lens
                  (Forget' fst) -- profunctor for fold
              )
          )
            (Tuple 0 (Tuple 1 (Tuple 2 3))) -- data structure
        )
    )

Yields:

purs compile: No files found using pattern: test/**/*.purs
[info] Build succeeded.
C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Data.Tuple\index.js:64
    return v.value1;
             ^

TypeError: Cannot read property 'value1' of undefined
    at Object.snd (C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Data.Tuple\index.js:64:14) 
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Data.Profunctor.Costar\index.js:98:59  
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Data.Identity\index.js:58:16
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Data.Profunctor.Costar\index.js:99:15  
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Main\index.js:56:20
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Main\index.js:33:16
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Main\index.js:29:16
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Main\index.js:20:24
    at C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Main\index.js:33:16
    at Object.<anonymous> (C:\Users\MikeSolomon\devel\random-scripts\free-monoid\output\Main\index.js:90:226)
[error] Running failed; exit code: 1

Expected behavior

Not quite sure... definitely not a crash, but it's still unclear what the expected would be.

Is the `Set` instance of `ix` a well-behaved optic?

profunctor-lenses has the ix function to produce 0-or-1 (“affine”) Traversals. It’s nice for arrays and maps. I noticed it also has an instance for Set. Fooling around, I saw the following:

     > result = set (ix "foo") unit Set.empty
     > result
     (fromFoldable ("foo" : Nil))

    > preview (ix "foo") result
    Nothing

This is peculiar in several ways:

  1. You cannot use (ix “foo”) to insert a new value into a Map:

    > set (ix "foo") "bar" Map.empty
    (fromFoldable [])

    … and yet you can with a Set.

  2. I’m not sure what form the set-get optics law should take with ix optics. But you can’t get what you can set, which seems odd. Actually, as far as I can tell, you can’t view or preview anything in a Set:

    > preview (ix "foo") (Set.singleton "foo")
    Nothing
    
    > view (ix "foo") (Set.singleton "foo")
    unit

Is the instance for Set a well-behaved optic? Should it be?

Maintainer?

I'm listed as maintainer here. Would people prefer I move this under paf31 and actually continue to maintain it, or that we find a new maintainer?

add icompose

i just found some functions that might be worth being added. But i don't really know where to add them and don't have the time to prepare a PR. So here we go:

mapIndex :: forall i j s t a b.
  (i -> j) -> IndexedTraversal i s t a b -> IndexedTraversal j s t a b
mapIndex fi tr = iwander \f -> itraverseOf tr (f <<< fi)

icompose :: forall i j k s' t' s t a b.
  (i -> j -> k) ->
  IndexedTraversal i s' t' s t ->
  IndexedTraversal j s t a b ->
  IndexedTraversal k s' t' a b
icompose ijk trO trI = iwander \f -> itraverseOf trO \i -> itraverseOf trI \j -> f (ijk i j)

icompose is inspired by
http://hackage.haskell.org/package/lens-4.15.1/docs/Control-Lens-Indexed.html#v:icompose

this way it's possible to combine IndexedTraversals:

test :: Array (Array Int)
test = [[1,2,3],[4,5,6]]

nested :: forall t1 t2 a b. (Traversable t1, Traversable t2) => IndexedTraversal (Tuple Int Int) (t1 (t2 a)) (t1 (t2 b)) a b
nested = icompose Tuple (positions traversed) (positions traversed)

comTest :: List (Tuple (Tuple Int Int) Int)
comTest = itoListOf nested test

-- comTest = ((Tuple (Tuple 0 0) 1) : (Tuple (Tuple 0 1) 2) : (Tuple (Tuple 0 2) 3) : (Tuple (Tuple 1 0) 4) : (Tuple (Tuple 1 1) 5) : (Tuple (Tuple 1 2) 6) : Nil)
-- or prettied up: [((0,0),1), ((0,1),2), ((0,2),3), ((1,0),4), ((1,1),5), ((1,2),6)]

affineStore function

I was looking for a function similar to lensStore but where some constructors of the ADT did not contain the inner value. After a day of learning lenses I came up with the following:

affineStore
  :: forall s t t' a b
   . (t' -> t)
  -> ALens s t' a b
  -> s
  -> Tuple (b -> t) (Either t a)
affineStore f l = withLens l go
  where
  go get set value =
    Tuple
      (f <<< set value)
      (Right $ get value)

ignoredAffineStore :: forall t a b. t -> Tuple (b -> t) (Either t a)
ignoredAffineStore wrapper = Tuple (const wrapper) (Left wrapper)

data Adt
  = X { x :: Int, y :: String }
  | Y { a :: Int, b :: Number }
  | Z { e :: Char }

_x :: forall s r. Lens' { x :: s | r } s
_x = prop (Proxy :: _ "x")

_a :: forall s r. Lens' { a :: s | r } s
_a = prop (Proxy :: _ "a")

_valueInAdt :: AffineTraversal' Adt Int
_valueInAdt = affineTraversal' case _ of
    X value   -> affineStore X _x value
    Y value   -> affineStore Y _a value
    adt@(Z _) -> ignoredAffineStore adt

Here the functions affineStore and ignoredAffineStore can be used in a similar way to lensStore. I have checked that it all follows affine traversal laws, I can send over the tests.

My question is whether these are useful functions to have in the lenses package. It is very useful for what I'm building and it seems there is no other way of doing it this comfortably.

Should prism and lens be defined as

prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
prism setter getter pab = dimap getter (either id setter) (right pab)

Then there won't be unnecessary rmap preprocessing.

lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens getter setter pab = dimap (\s -> (getter s, s)) (\(b, s) -> setter s b) (first' pab)

and here we won't apply setter to s before actually needed (making of pair is unavoidable)

Documentation: how do `is`, `isn't`, and `matching` work?

I'm a newbie writing documentation for newbies, in this case about Prisms.

Question 1: There are three functions that seem to be about checking if a value is the one a prism focuses on: is, isn't, and matching. matching is the only one I can get to work. How does one use is and isn't?

Question 2: Now let's consider this type:

data Fill
  = Solid Color
  | LinearGradient Color Color Percent
  | RadialGradient Color Color Point
  | NoFill

Let's suppose I create a prism that selects out the Solid case:

chooseSolidM fill =
  case fill of
    Solid x -> Just x
    _ -> Nothing

solidM = prism' Solid chooseSolidM

Given values solid and linear, matching gives me these results:

> matching solidM linear
(Left (LinearGradient rgba 255 255 255 1.0 rgba 0 0 0 1.0 3.3%))

> matching solidM solid
(Right rgba 255 255 255 1.0)

That seems sensible: If the match is "right", the value is extracted; otherwise, you are "left" with the original value. But let's look at what happens when we look at a specific (only) Solid value:

whiteSolid =
  only (Solid Color.white)

matching works differently:

> matching whiteSolid (Solid Color.black)
(Left (Solid rgba 0 0 0 1.0))

> matching whiteSolid (Solid Color.white)
(Right unit)

I understand why the types dictate those results, but I don't understand the inconsistency between how Prisms created with prism' (or prism) and those created with only behave. Why don't they both provide the failing value?

Where do we put the lenses and traversals?

The Haskell lens library is infamous in the community for its dependencies and perceived heaviness, mostly because it aims to be "batteries included" and provide lenses, traversals, prisms etc. for a whole lot of libraries. This has the advantage of being incredibly convenient, because it spares us from defining the same lens each and every time we need it. However, many applications or libraries might only want to use a the core features and two or three lenses, rather than the entire bulk. Starting fresh, we have at least four options to choose from for purescript lenses:

  1. Include lenses/prisms/traversals in the lens library. We would need prisms for Either, Tuple, JSON etc., some indexing type class for Map etc. This would pull in a whole bunch of dependencies.
  2. Like the refractor library for van Laarhoven lenses - that appears pretty much dead -, we could add an
    extra library that pulls in all the dependencies and defines the lenses. This way, if one is a purist and wants to use the lens core, one can use the core library; if one wants convenience, import refractor.
  3. Distribute the stuff to the package that defines the associated data type, i.e. the prisms for Either in purescript-either, the prisms for Tuple in purescript-tuple etc. This may need a bit of convincing of maintainers of some libraries and would add a profunctor dependency to nearly anything (maybe profunctors could be moved to the core library?). Personally, this option is my favourite.
  4. Don't care. After all, user code might define _1, _Right or _Object everytime it is needed.

Type mismatch between Getter/Fold and to in 0.4.2. (Star Const -> Forget related)

newtype XPathPoint = XPathPoint
  { selector :: String
  , offset   :: Int
  }

selector :: GetterP XPathPoint String
selector = to $ \ (XPathPoint s) -> s.selector

Gives this compile error:

at /Users/bkolera/src/benaud/src/CommentManager/Types.purs line 48, column 12 - line 50, column 1

  Could not match type

    Forget

  with type

    Star


while trying to match type Forget
  with type Star
while checking that expression (($) to) (\_17 ->
                                           case _17 of
                                             (XPathPoint s) -> ...
                                        )
  has type Forget String String String -> Forget String XPathPoint XPathPoint
in value declaration selector

I note that Fold changed from

type Fold r s t a b = Optic (Star (Const r)) s t a b

in 0.3.5 to this in 0.4.x (I'm using 0.4.2)

type Fold r s t a b = Optic (Forget r) s t a b

Which is the source of the type error, but don't quite have a clue whether the library is actually broken in 0.4.0 or I need to do something slightly differently.

New release?

It would be handy to have a new release with the 0.12 support.

Documentation

Would there be interest in API documentation containing more words and examples?

Perhaps something not to the level of http://marick.github.io/suchwow/such.better-doc.html, but definitely geared toward someone learning how to learn lenses.

More generally, the Haskell lens documentation, including the tutorial, is not well-suited to people learning lenses. It's especially difficult for someone, like me and I hope many others, not coming to PureScript from Haskell, since there are differences in organization and so on.

It would not be hard to make the PureScript lens documentation the reference standard. A fair amount of work, but not hard work.

This is the sort of thing I could throw myself into, given support. I'll already (probably) be doing some of the work in https://leanpub.com/outsidefp

Instances for HashMap

I noticed that many of the optics in this package have instances for Map but not for HashMap. I would find it useful to have access to Ix and At (among others) for HashMaps. Would you be willing to accept a PR for this?

fuseSetters function

Hello!

We've been using a function called fuseSetters a fair bit in production to speed up code where several setters are called on complex records (in our case, adding custom OpenAPI tags to a large OpenAPI spec).

Here is the function with the output. If folks find it useful, I can make a PR to include it in the library:

module Main where

import Prelude
import Data.Lens (Setter', _1, _2, over)
import Data.Tuple (Tuple(..), fst, snd)
import Effect (Effect)
import Effect.Class.Console (log)

fuseSetters :: forall s a b c. Setter' a b -> Setter' a c -> Setter' s a -> Setter' s (Tuple (b -> b) (c -> c))
fuseSetters a b c l = over c (over a fa <<< over b fb)
  where
  t = l $ Tuple identity identity

  fa = fst t

  fb = snd t

main :: Effect Unit
main = do
  log
    ( show
        $ over
            (fuseSetters (_1 <<< _1) (_2 <<< _2) (_2 <<< _2 <<< _2))
            (const $ Tuple (const 42) (const 53))
            (Tuple 1 (Tuple 2 (Tuple 3 (Tuple (Tuple 0 1) (Tuple 5 8)))))
    )

yields

07:06 meeshkan-abel@Abel:/tmp/lenz$ spago run
[info] Installation complete.
[info] Build succeeded.
(Tuple 1 (Tuple 2 (Tuple 3 (Tuple (Tuple 42 1) (Tuple 5 53)))))

Thanks and let me know!

Update Array inside Array

x :: Array (Array Int)
x = [[1,2,3]] # ix 0 <<< ix 2 .~ 11
  No type class instance was found for

    Data.Lens.Index.Index (Array (Array Int))
                          Int
                          _0

  The instance head contains unknown type variables. Consider adding a type annotation.

I created this function aix

aix :: forall a. Int -> TraversalP (Array a) a
aix n = ix n
x = [[1,2,3]] # aix 0 <<< aix 2 .~ 11

Is there any better workaround?

_2 implemented in terms of `second` doesn't work too well

Starting with:

type X = { page :: Tuple (Maybe String) Int }

_page :: LensP X (Tuple (Maybe String) Int)
_page = lens _.page (_ { page = _ })

Trying to use:

_page <<< _2

Results in:

  Could not match type

    Function (Star (Const _0) _0 _1)

  with type

    Object

But using the original definitions we had works fine:

_snd :: forall a b c. Lens (Tuple c a) (Tuple c b) a b
_snd = lens snd (\(Tuple c _) b -> Tuple c b)

_page <<< _snd

@paf31 I guess this is more a bug for the typechecker than for this library, should I open something on the compiler repo?

`view` could be implemented in terms of MonadAsk

Generalizing view is nice, as it allows you to use view in a MonadAsk context like use in a MonadState context.

-- | View the focus of a `Getter`.
view :: forall s t a b m. MonadAsk s m => Getter s t a b -> m a
view l = ask >>= unwrap (l (Forget id))

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.