Where communities thrive

• Join over 1.5M+ people
• Join over 100K+ communities
• Free without limits
Activity
Gavin Bisesi
@Daenyth
Either is a pretty easy one
I usually factor typeclass dependencies to be precise for code isolation and semantic information to the reader, rather than so I can actually use non-IO in tests
Billzabob
@Billzabob
Why does Free in cats have Pure, Suspend, and FlatMapped but in Haskell it just has Pure a and Free (f ( Free f a))?
Gavin Bisesi
@Daenyth
Probably because haskell is always lazy
Fabio Labella
@SystemFw
stack safety
cats Free is also a bit different in that it factors in Coyoneda as well, so it's actually closer to Coyoneda in haskell
Billzabob
@Billzabob
Haven't heard of Coyoneda. That's quite the name. How do you pronounce it?
Fabio Labella
@SystemFw

a good way of looking at it is noting how Monad can be expressed as either (forgetting Applicative)

class Functor f => Monad f where
pure :: a -> f a
join :: f (f a) -> f a

or

class Monad f where
pure :: a -> f a
(>>=) ::  f a -> (a -> f b) -> f b

.
The first definition gives rise to

data Free f a = Pure a | Roll (f (Free f a))
instance Functor f => Monad (Free f) where ...

and your algebra looks this way:

data Alg a = Put String a | Get String (String -> a)
instance Functor Alg where

The second definition, which is Operational (and cats Free) gives rise to

data Free f a where
Pure  ::  a ->  Free fa
FlatMap ::  f a  -> (a -> Free f b) -> Free f b

instance Monad (Free f a) -- note no Functor

and your algebra looks this way

data Alg a where
Put :: String -> Alg ()
Get :: String -> Alg String

and no Functor needed

at first people thought these two were two different things
Fabio Labella
@SystemFw
but it turns out the second (Operational) can be understood as being the first, except f is Coyoneda f , and Coyoneda is basically the Free Functor
which is why you don't need to explicitly declare a Functor for your algebra
class Functor f where
fmap :: (a -> b) -> f a -> f b

data Coyoneda f a where
Fmap :: (a -> b) -> f b -> Coyoneda f a
in Scala, for a while we were literally doing Free[Coyoneda[F, ?], A] (with a FreeC type synonym)
until it got folded in, and then it ended up looking like Operational
Rob Norris
@tpolecat
Free of Coyoneda was the :fire: for a long time. It really opened things up.
Billzabob
@Billzabob
That's a lot to take in but I love when I get something new to learn about from here. One more question: Is there an implementation of a rose tree with the appropriate cats type-class instances somewhere or should I just try and roll my own?
Fabio Labella
@SystemFw
@Billzabob funnily enough, that's Cofree
using List as the pattern functor
Billzabob
@Billzabob
@SystemFw Interesting how often things seem to tie together like that.
Fabio Labella
@SystemFw
yet another way to look at Free (especially evident in the first version) is as a tree with a Functorful f of children, and values at the leaves (the Pure constructor is Leaf a, and Roll is the branch, with f children). If you look at Cofree, that's also a Tree with values at the branches instead, and again whose structure is determined by f, and that's a Rose Tree
data Free f a = Leaf a | Node f (Free f a)
data Cofree f a = Node a (f (Cofree f a))
type Rose = Cofree []
-- replace and you get
data Rose a = Node a [Rose a]
Igor Postanogov
@ipostanogov

Hi!

If I have Map[String, Int] & f: Int => ValidatedNec[String, Bool], I can get Map[String, ValidatedNec[String, Bool]] via mapValues.
Is there any way to get ValidatedNec[String, Map[String, Bool]] from it?

Oleg Pyzhcov
@oleg-py
import alleycats.std.map._ and then traverse?
Igor Postanogov
@ipostanogov
@oleg-py, it works, thanks!
Soren
@srnb_gitlab
How do I dropWhile a List[F[T]] based on F[T] => F[Boolean]?
A solution using sequencing is not what I want because I don't want to evaluate the F[T]s later in the list
Gavin Bisesi
@Daenyth
@srnb_gitlab I recommend fs2
Oleg Pyzhcov
@oleg-py
or manual recursion
Gavin Bisesi
@Daenyth
val lst: List[F[T]] = ???
fs2.Stream.emits(lst)  // Stream[Pure, F[T]]
.evalMap(identity)   // Stream[F, T]
.evalMap(t => cond(t).map(b => (t, b))) // Stream[F, (T, B)]
.dropWhile(tb => tb._2)
.map(_._1) // Stream[F, T]
Oleg Pyzhcov
@oleg-py
def dropWhileM[F[_]: Monad, A](list: List[F[A]])(fn: F[A] => F[Boolean]): F[List[F[A]]] = list match {
case fa :: fas => fn(fa).ifM( dropWhileM(fas)(fn), list.pure[F] )
case _ => list.pure[F]
}
wonder why you'd want F[A] => F[Boolean] instead of A => F[Boolean] tho
Luis Martinez
@luis3m
or even A => Boolean I'd say
Oleg Pyzhcov
@oleg-py
Well, that's quite common. "filename => file.exists" needs to go through an effect type
Luis Martinez
@luis3m
right
Oleg Pyzhcov
@oleg-py
Hmm...
def dropWhileM[F[_]: Monad, A](list: List[F[A]])(fn: F[A] => F[Boolean]): F[List[F[A]]] = {
list.tails.toStream
.map(_.orEmpty)
}
Gavin Bisesi
@Daenyth
needs moar tailRecM
Ivano Pagano
@ivanopagano
any way to generically build a Traversable instance from a collection ?
e.g. I have a List[A] and would like to build a T[A] where there's a Traversable[T]
this is some form of CanBuildFrom, semantically, yet I would rather avoid doing it procedurally
but I guess I need to be able to "unfold" rather than "fold" as in traverse
owww, sorry, I meant Traverse[T] of course
Gavin Bisesi
@Daenyth
I'm not sure there's a typeclass describing unfold
Ivano Pagano
@ivanopagano
I guess not, indeed
I guess this means that I may stop searching
Rob Norris
@tpolecat
@tpolecat I think he wants def unfoldWhatever[F[_]: Foldable, G[_]: ?Unfoldable?, A](as: F[A]): G[A] ( @ivanopagano is that right)