Extend one Traversal lens with another Traversal lens - purescript

Let's say I have a Node and it can have children and siblings and I have traversal lens implementations for them. How do I compose them into a single lens that traverses both children and siblings?
_children :: Traversal' Node Node
_children = ...
_siblings :: Traversal' Node Node
_siblings = ...
_relatives :: Traversal' Node Node
_relatives = ???
Seems like a very basic question, but I could not find any info on how to "add" one traversal to another.

This is the closest I've got using the wander function:
_relatives :: Traversal' Node Node
_relatives = wander tra
where
tra1 :: forall f. Applicative f => (Node -> f Node) -> Node → f Node
tra1 = traverseOf _children
tra2 :: forall f. Applicative f => (Node -> f Node) -> Node → f Node
tra2 = traverseOf _siblings
tra :: forall f. Applicative f => (Node -> f Node) -> Node → f Node
tra g w = lift2 combine fw' fw''
where
fw' = tra1 g w
fw'' = tra2 g w
combine (Node w') (Node w'') = Node (w' { siblings = w''.siblings })
If only I could get rid of this last line...
combine (Node w') (Node w'') = Node (w' { siblings = w''.siblings })
Ideally, my tra would be like so (chaining result of tra1 into tra2):
tra :: forall f. Monad f => (Node -> f Node) -> Node -> f Node
tra g w = tra2 g =<< tra1 g w
But I can't do that, because wander asks for Applicative constraint and not a Monad. And I can't chain the results of Applicative.
I can also do this generically if my Node implements Semigroup:
tra :: forall f. Applicative f => (Node -> f Node) -> Node -> f Node
tra g w = lift2 append fw' fw''
where
fw' = tra1 g w
fw'' = tra2 g w
But I don't have Semigroup for my real use-case...
Is there really no generic way to combine two traversals?
I really hope someone can come up with better approach. If not, I'll mark this answer as accepted after a while.
EDIT:
Turns out I'm not the only one wishing to do that, and apparently it's impossible due to the "sequencing" nature of such transformation - it requires a Monad while we only have an Applicative https://github.com/ekmett/lens/issues/109
Going to accept this answer since there is probably no better answer than "there is no answer".

Related

API for handling polymothinc records

It is a little bit custom issue, is not contrived, but just simplified as possible.
-- this record that has fn that handles both x and y,
-- x and y supposed to be Functors, a arbitrary param for x/y, r is arbitrary result param
type R0 a x y r =
{ fn :: x a -> y a -> r
}
-- this record that has fn that handles only x
type R1 a x r =
{ fn :: x a -> r
}
What I want is a common API (function) that could handle values of R0 and R1 types.
So I do a sum type
data T a x y r
= T0 (R0 a x y r)
| T1 (R1 a x r)
And I declare this function, there is a constraint that x and y have to be Functors.
some :: ∀ a x y r.
Functor x =>
Functor y =>
T a x y r -> a
some = unsafeCoerce -- just stub
Then try to use it.
data X a = X { x :: a}
data Y a = Y { y :: a }
-- make X type functor
instance functorX :: Functor X where
map fn (X val) = X { x: fn val.x }
-- make Y type functor
instance functorY :: Functor Y where
map fn (Y val) = Y { y: fn val.y }
-- declare functions
fn0 :: ∀ a. X a -> Y a -> Unit
fn0 = unsafeCoerce
fn1 :: ∀ a. X a -> Unit
fn1 = unsafeCoerce
Trying to apply some:
someRes0 = some $ T0 { fn: fn0 } -- works
someRes1 = some $ T1 { fn: fn1 } -- error becase it can not infer Y which should be functor but is not present in f1.
So the question is: Is it possible to make such API work somehow in a sensible/ergonomic way (that would not require some addition type annotations from a user of this API)?
I could apparently implement different functions some0 and some1 for handling both cases, but I wonder if the way with a single function (which makes API surface simpler) is possilbe.
And what would be other suggestions for implementing such requirements(good API handling such polymorphic record types that differ in a way described above, when one of the records has exessive params)?
You should make T1 and T0 separate types and then make function some itself overloaded to work with them both:
data T0 x y r a = T0 (R0 a x y r)
data T1 x r a = T1 (R1 a x r)
class Some t where
some :: forall a. t a -> a
instance someT0 :: (Functor x, Functor y) => Some (T0 x y r) where
some = unsafeCoerce
instance someT1 :: Functor x => Some (T1 x r) where
some = unsafeCoerce
An alternative, though much less elegant, solution would be to have the caller of some explicitly specify the y type with a type signature. This is the default approach in situations when a type can't be inferred by the compiler:
someRes1 :: forall a. a
someRes1 = some (T1 { fn: fn1 } :: T a X Y Unit)
Note that I had to add a type signature for someRes1 in order to have the type variable a in scope. Otherwise I couldn't use it in the type signature T a X Y Unit.
An even more alternative way to specify y would be to introduce a dummy parameter of type FProxy:
some :: ∀ a x y r.
Functor x =>
Functor y =>
FProxy y -> T a x y r -> a
some _ = unsafeCoerce
someRes0 = some FProxy $ T0 { fn: fn0 }
someRes1 = some (FProxy :: FProxy Maybe) $ T1 { fn: fn1 }
This way you don't have to spell out all parameters of T.
I provided the latter two solutions just for context, but I believe the first one is what you're looking for, based on your description of the problem mentioning "polymorphic methods". This is what type classes are for: they introduce ad-hoc polymorphism.
And speaking of "methods": based on this word, I'm guessing those fn functions are coming from some JavaScript library, right? If that's the case, I believe you're doing it wrong. It's bad practice to leak PureScript-land types into JS code. First of all JS code might accidentally corrupt them (e.g. by mutating), and second, PureScript compiler might change internal representations of those types from version to version, which will break your bindings.
A better way is to always specify FFI bindings in terms of primitives (or in terms of types specifically intended for FFI interactions, such as the FnX family), and then have a layer of PureScript functions that transform PureScript-typed parameters to those primitives and pass them to the FFI functions.

Similar record types in a list/array in purescript

Is there any way to do something like
first = {x:0}
second = {x:1,y:1}
both = [first, second]
such that both is inferred as {x::Int | r} or something like that?
I've tried a few things:
[{x:3}] :: Array(forall r. {x::Int|r}) -- nope
test = Nil :: List(forall r. {x::Int|r})
{x:1} : test -- nope
type X r = {x::Int | r}
test = Nil :: List(X) -- nope
test = Nil :: List(X())
{x:1} : test
{x:1, y:1} : test -- nope
Everything I can think of seems to tell me that combining records like this into a collection is not supported. Kind of like, a function can be polymorphic but a list cannot. Is that the correct interpretation? It reminds me a bit of the F# "value restriction" problem, though I thought that was just because of CLR restrictions whereas JS should not have that issue. But maybe it's unrelated.
Is there any way to declare the list/array to support this?
What you're looking for is "existential types", and PureScript just doesn't support those at the syntax level the way Haskell does. But you can roll your own :-)
One way to go is "data abstraction" - i.e. encode the data in terms of operations you'll want to perform on it. For example, let's say you'll want to get the value of x out of them at some point. In that case, make an array of these:
type RecordRep = Unit -> Int
toRecordRep :: forall r. { x :: Int | r } -> RecordRep
toRecordRep {x} _ = x
-- Construct the array using `toRecordRep`
test :: Array RecordRep
test = [ toRecordRep {x:1}, toRecordRep {x:1, y:1} ]
-- Later use the operation
allTheXs :: Array Int
allTheXs = test <#> \r -> r unit
If you have multiple such operations, you can always make a record of them:
type RecordRep =
{ getX :: Unit -> Int
, show :: Unit -> String
, toJavaScript :: Unit -> Foreign.Object
}
toRecordRep r =
{ getX: const r.x
, show: const $ show r.x
, toJavaScript: const $ unsafeCoerce r
}
(note the Unit arguments in every function - they're there for the laziness, assuming each operation could be expensive)
But if you really need the type machinery, you can do what I call "poor man's existential type". If you look closely, existential types are nothing more than "deferred" type checks - deferred to the point where you'll need to see the type. And what's a mechanism to defer something in an ML language? That's right - a function! :-)
newtype RecordRep = RecordRep (forall a. (forall r. {x::Int|r} -> a) -> a)
toRecordRep :: forall r. {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
allTheXs = test <#> \(RecordRep r) -> r _.x
The way this works is that RecordRep wraps a function, which takes another function, which is polymorphic in r - that is, if you're looking at a RecordRep, you must be prepared to give it a function that can work with any r. toRecordRep wraps the record in such a way that its precise type is not visible on the outside, but it will be used to instantiate the generic function, which you will eventually provide. In my example such function is _.x.
Note, however, that herein lies the problem: the row r is literally not known when you get to work with an element of the array, so you can't do anything with it. Like, at all. All you can do is get the x field, because its existence is hardcoded in the signatures, but besides the x - you just don't know. And that's by design: if you want to put anything into the array, you must be prepared to get anything out of it.
Now, if you do want to do something with the values after all, you'll have to explain that by constraining r, for example:
newtype RecordRep = RecordRep (forall a. (forall r. Show {x::Int|r} => {x::Int|r} -> a) -> a)
toRecordRep :: forall r. Show {x::Int|r} => {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
showAll = test <#> \(RecordRep r) -> r show
Passing the show function like this works, because we have constrained the row r in such a way that Show {x::Int|r} must exist, and therefore, applying show to {x::Int|r} must work. Repeat for your own type classes as needed.
And here's the interesting part: since type classes are implemented as dictionaries of functions, the two options described above are actually equivalent - in both cases you end up passing around a dictionary of functions, only in the first case it's explicit, but in the second case the compiler does it for you.
Incidentally, this is how Haskell language support for this works as well.
Folloing #FyodorSoikin answer based on "existential types" and what we can find in purescript-exists we can provide yet another solution.
Finally we will be able to build an Array of records which will be "isomorphic" to:
exists tail. Array { x :: Int | tail }
Let's start with type constructor which can be used to existentially quantify over a row type (type of kind #Type). We are not able to use Exists from purescript-exists here because PureScript has no kind polymorphism and original Exists is parameterized over Type.
newtype Exists f = Exists (forall a. f (a :: #Type))
We can follow and reimplement (<Ctrl-c><Ctrl-v> ;-)) definitions from Data.Exists and build a set of tools to work with such Exists values:
module Main where
import Prelude
import Unsafe.Coerce (unsafeCoerce)
import Data.Newtype (class Newtype, unwrap)
newtype Exists f = Exists (forall a. f (a :: #Type))
mkExists :: forall f a. f a -> Exists f
mkExists r = Exists (unsafeCoerce r :: forall a. f a)
runExists :: forall b f. (forall a. f a -> b) -> Exists f -> b
runExists g (Exists f) = g f
Using them we get the ability to build an Array of Records with "any" tail but we have to wrap any such a record type in a newtype before:
newtype R t = R { x :: Int | t }
derive instance newtypeRec :: Newtype (R t) _
Now we can build an Array using mkExists:
arr :: Array (Exists R)
arr = [ mkExists (R { x: 8, y : "test"}), mkExists (R { x: 9, z: 10}) ]
and process values using runExists:
x :: Array [ Int ]
x = map (runExists (unwrap >>> _.x)) arr

generalize purescript function using MonadAff

I have a question about generalizing. Starting with this function:
test0 :: String -> String
test0 s = s
we can generalize it in its argument:
test1 :: forall a. Show a => a -> String
test1 s = show s
or in its functional result:
test12 :: forall a. Show a => String -> a
test12 s = s
Now consider the following function:
test2 :: forall e. Aff e Int
test2 s = pure 0
I would like to generalize it in its functional result:
test3 :: forall e m. MonadAff e m => m e Int
test3 s = pure 0
However, I now get an error:
Could not match kind type with kind # Control.Monad.Eff.Effect while checking the kind of MonadAff e m => m e Int in value declaration test3.
I cannot understand why. Moreover, I've found an example of similar such generalizing in Hyper.Node.Server, for example in this type:
write :: forall m e. MonadAff e m => Buffer -> NodeResponse m e
The constraint MonadAff e m asserts that the monad m somehow wraps Aff e somewhere inside. But it doesn't assert that monad m itself must have a type argument e. That would be awfully restrictive, wouldn't it?
Therefore, when constructing your return type, don't apply m to e:
test3 :: forall e m. MonadAff e m => m Int
test3 = pure 0
The example you found is quite different. Here, the function is not returning a value in m, like in your test3, but rather a value NodeResponse, which is a wrapper around a function that returns m Unit.

standard specialization of Either where type of Left and Right is the same

Is there a standard specialization of Either in Haskell or Scala that makes the types contained in the Left and Right the same type?
In Haskell, I want something like this:
data SpecializedEither a = Left a | Right a
This might also be considered a slight generalization of Maybe that makes Nothing hold a value.
edit: Ganesh raises a very good point that a Monad instance can't be defined for this type. Is there a better way to do what I am trying to do?
There's a standard Monad instance on ((,) e) so long as e is a Monoid
instance Monoid e => Monad ((,) e) where
return a = (mempty, a)
(e1, a) >>= f = let (e2, b) = f a in (e1 <> e2, b)
Since Either a a and (Bool, a) are isomorphic (in two ways), we get a Monad instance as soon as we pick a Monoid for Bool. There are two (really four, see comments) such Monoids, the "and" type and the "or" type. Essentially, this choice ends up deciding as to whether the Left or Right side of your either is "default". If Right is default (and thus Left overrides it) then we get
data Either1 a = Left1 a | Right1 a
get1 :: Either1 a -> a
get1 (Left1 a) = a
get1 (Right1 a) = a
instance Monad Either1 where
return = Right1
x >>= f = case (x, f (get1 x)) of
(Right1 _, Right1 b) -> Right1 b
(Right1 _, Left1 b) -> Left1 b
(Left1 _, y ) -> Left1 (get1 y)
How about:
type Foo[T] = Either[T, T]
val x: Foo[String] = Right("")
// Foo[String] = Right()

Folding flatMap/bind over a list of functions (a.k.a. Name That Combinator!)

In the process of writing a simple RPN calculator, I have the following type aliases:
type Stack = List[Double]
type Operation = Stack => Option[Stack]
... and I have written a curious-looking line of Scala code:
val newStack = operations.foldLeft(Option(stack)) { _ flatMap _ }
This takes an initial stack of values and applies a list of operations to that stack. Each operation may fail (i.e. yields an Option[Stack]) so I sequence them with flatMap. The thing that's somewhat unusual about this (in my mind) is that I'm folding over a list of monadic functions, rather than folding over a list of data.
I want to know if there's a standard function that captures this "fold-bind" behavior. When I'm trying to play the "Name That Combinator" game, Hoogle is usually my friend, so I tried the same mental exercise in Haskell:
foldl (>>=) (Just stack) operations
The types here are:
foldl :: (a -> b -> a) -> a -> [b] -> a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
So the type of my mystery foldl (>>=) combinator, after making the types of foldl and (>>=) line up, should be:
mysteryCombinator :: Monad m => m a -> [a -> m a] -> m a
... which is again what we'd expect. My problem is that searching Hoogle for a function with that type yields no results. I tried a couple other permutations that I thought might be reasonable: a -> [a -> m a] -> m a (i.e. starting with a non-monadic value), [a -> m a] -> m a -> m a (i.e. with arguments flipped), but no luck there either. So my question is, does anybody know a standard name for my mystery "fold-bind" combinator?
a -> m a is just a Kleisli arrow with the argument and result types both being a. Control.Monad.(>=>) composes two Kleisli arrows:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
Think flip (.), but for Kleisli arrows instead of functions.
So we can split this combinator into two parts, the composition and the "application":
composeParts :: (Monad m) => [a -> m a] -> a -> m a
composeParts = foldr (>=>) return
mysteryCombinator :: (Monad m) => m a -> [a -> m a] -> m a
mysteryCombinator m fs = m >>= composeParts fs
Now, (>=>) and flip (.) are related in a deeper sense than just being analogous; both the function arrow, (->), and the data type wrapping a Kleisli arrow, Kleisli, are instances of Control.Category.Category. So if we were to import that module, we could in fact rewrite composeParts as:
composeParts :: (Category cat) => [cat a a] -> cat a a
composeParts = foldr (>>>) id
(>>>) (defined in Control.Category) is just a nicer way of writing as flip (.).
So, there's no standard name that I know of, but it's just a generalisation of composing a list of functions. There's an Endo a type in the standard library that wraps a -> a and has a Monoid instance where mempty is id and mappend is (.); we can generalise this to any Category:
newtype Endo cat a = Endo { appEndo :: cat a a }
instance (Category cat) => Monoid (Endo cat a) where
mempty = Endo id
mappend (Endo f) (Endo g) = Endo (f . g)
We can then implement composeParts as:
composeParts = appEndo . mconcat . map Endo . reverse
which is just mconcat . reverse with some wrapping. However, we can avoid the reverse, which is there because the instance uses (.) rather than (>>>), by using the Dual a Monoid, which just transforms a monoid into one with a flipped mappend:
composeParts :: (Category cat) => [cat a a] -> cat a a
composeParts = appEndo . getDual . mconcat . map (Dual . Endo)
This demonstrates that composeParts is a "well-defined pattern" in some sense :)
The one starting with a non-monadic value is (modulo flip)
Prelude> :t foldr (Control.Monad.>=>) return
foldr (Control.Monad.>=>) return
:: Monad m => [c -> m c] -> c -> m c
(or foldl)
(Yes, I know this doesn't answer the question, but the code layout in comments isn't satisfactory.)