These are chat archives for typelevel/cats

20th
Jun 2018
dadepo
@dadepo
Jun 20 00:42

Is there any recommendation on which to go for between cats.Applicative[Option].apX and cats.Applicative[Option].mapX or it boils down to personal preference?

I personally find the .apX variant more intuitive as i think it fits more into the general idea of applicative: applying functions to values, albeit in a context. The .mapX variants feel slightly out of place for me :/

thinking more about it, I am guessing the map thingies need to be in there since Applicatives extends Functors
Rob Norris
@tpolecat
Jun 20 01:30
I never use either directly. The (op1, op2).mapN(f) syntax is usually fine.
dadepo
@dadepo
Jun 20 05:33
I guess thats how its gonna play out in practice...I am still going through the Scala with Cats book (underscore), and was a little bit trippy by the explanation of Applicative/Semigroupal and similar functions in the companion objects of both typeclasses
Jakub Kozłowski
@kubukoz
Jun 20 09:45
@dadepo for me it's usually much easier to work with mapX instead of apX but YMMV
having an F[A => C] would require me to do map on my F[B] first, and with mapX I can get it done without additional maps
Fabio Labella
@SystemFw
Jun 20 10:20
scala' syntax is really not geared towards ap
in haskell a chain of map and then ap (times arity) works really nice and you get the f <$> fa <*> fb <*> fc out of the box without any magic. mapN is magic but works really nice here, and I recommend that
JsonFn
@JsonFn
Jun 20 12:55
Following exercise at https://github.com/scala-exercises/exercises-cats/blob/master/src/main/scala/catslib/Semigroup.scala I import cats.implicits. cats.kernel.Semigroup, and cats.syntax.semigroup.. But when trying with code one |+| two, compiler complains value |+| is not a member of Option[Int]. Anything I miss so it can't get compiled?
Rutvik Patel
@heyrutvik
Jun 20 12:57
Hey guys, Can I ask Haskell's do notation related question?
Fabio Labella
@SystemFw
Jun 20 12:59
@heyrutvik yes
@JsonFn in this case you are missing cats.instances.option._
Rutvik Patel
@heyrutvik
Jun 20 13:00
thanks @SystemFw :)
here https://github.com/heyrutvik/playground/blob/master/haskell/graham-hutton/src/FunctionalParsers.hs#L40
p' and p'' working as expected.. but phas error. I think all of them has same meaning but it's not working.
Jakub Kozłowski
@kubukoz
Jun 20 13:00
he said he imported cats.implicits though. @JsonFn do you have import cats.implicits._ with the underscore?
Fabio Labella
@SystemFw
Jun 20 13:00
However I would advise forgetting about specific imports and just going with import cats._, implicits._ (and data._ if you need things like Validated), and removing other imports
if you import implicits._ then you have to not have syntax or instances, or they will conflict
Jakub Kozłowski
@kubukoz
Jun 20 13:01
(also, it might be due to a conflict because you bring the semigroup syntax twice - once in implicits._ and syntax.semigroup._)
yeah this
JsonFn
@JsonFn
Jun 20 13:01
yes i have the statement import cats.implicits._ at the beginning of scala file.
Fabio Labella
@SystemFw
Jun 20 13:01
then remove the syntax one
just go with this import cats._, implicits._ and nothing else (apart from data._ when you need it)
@heyrutvik let me have a look
Rutvik Patel
@heyrutvik
Jun 20 13:03
@SystemFw sure
JsonFn
@JsonFn
Jun 20 13:04
Looks like import cats.syntax.semigroup._ causes the conflict. @SystemFw Thanks for help!
Fabio Labella
@SystemFw
Jun 20 13:05
yeah, any syntax or instances import will conflict with implicits
Rutvik Patel
@heyrutvik
Jun 20 14:46
@SystemFw I think I found the issue. I can't use do notation because I haven't defined monad instance for Parser type. :)
Fabio Labella
@SystemFw
Jun 20 14:46
oh sorry, I fixed your problem but forgot to text you
so, there are three things you can do
if you want to keep your code exactly as it is
you need to add this on top of your file
{-# Language RebindableSyntax #-}
that's option 1
option 2 is to keep your code as is but define a monad instance. That will require `{-# Language TypeSynonymInstances #-}
or
option 3, which I recommend
is change Parser to be a newtype instead, and define a Monad instance for it
no extensions needed
@heyrutvik
Rutvik Patel
@heyrutvik
Jun 20 14:50
Ohh.. that {-# xxx #-} is new thing for me! :smile: Where can I find more information on that?
Fabio Labella
@SystemFw
Jun 20 14:50
{-# Language .... #-} enables language extensions
there are dozens of those, from obscure, syntax only enhancements to very important, commonplace extensions
honestly, I'd recommend not going into the rabbit hole for now
define a newtype for Parser (which you should do anyway)
and add a Monad/Applicative/Functor instance for it
Rutvik Patel
@heyrutvik
Jun 20 14:52

Great..

honestly, I'd recommend not going into the rabbit hole for now

Sure.. :)
Thanks man for the help! Appreciate it :)

Fabio Labella
@SystemFw
Jun 20 14:53
no problem :)
this is the starting point:
newtype Parser a = Parser { parse :: String -> [(a, String)] }
Rutvik Patel
@heyrutvik
Jun 20 14:56
Cool.. I haven't introduced to newtype yet in the book.
So here we are defining Parser type with one type parameter, right?
Is parse a method for the Parser values? :confused:
@SystemFw
Fabio Labella
@SystemFw
Jun 20 15:09
ah, you haven't seen records yet
then nevermind, do it like this
newtype Parser a = Parser (String -> [(a, String)] )
parse :: Parser a -> String -> [(a, String)]
parse (Parser p) x = p x
or like this if you don't want newtype
data Parser a = Parser (String -> [(a, String)] )
parse :: Parser a -> String -> [(a, String)]
parse (Parser p) x = p x
Fabio Labella
@SystemFw
Jun 20 15:16
@heyrutvik
Rutvik Patel
@heyrutvik
Jun 20 15:34
Nope.. not records yet! :)
apparently, there is very subtle difference between newtype and data because both snippet are identical other than that!
never mind.. I will keep reading the book, eventually everything will be covered ;) thanks @SystemFw. BTW I liked your username! :thumbsup:
Fabio Labella
@SystemFw
Jun 20 15:58
:)
you can ignore the difference between newtype and data for now
in a nutshell, newtype guarantees zero-cost wrapping (so no boxing) for one argument product types, which implies slight differences with regards to laziness. All irrelevant for now
Rutvik Patel
@heyrutvik
Jun 20 16:00
Cool.. got it :thumbsup:
Rob Norris
@tpolecat
Jun 20 16:13
@SystemFw hey I'm sitting here with @smarter and we got the higher-rank fmap to work. amazeballs
Luka Jacobowitz
@LukaJCB
Jun 20 16:16
That’s awesome :clap:
Itamar Ravid
@iravid
Jun 20 16:35
Even more impressive than a bash one-liner ;)
Luka Jacobowitz
@LukaJCB
Jun 20 16:48

I’ve got a problem for you folks.
This is what I have so far:

trait Algebra[F[_]] {
  def foo(x: String): F[String]
}

case class Foo[A](f: Int => IO[A])

def bar(a: Int): Algebra[IO] = …

def transformed: Algebra[Foo] = new Algebra[Foo] {
  def foo(x: String): Foo[String] = Foo(n => bar(n).foo(x))
}

Now I want to be able to abstract this for any Alg[_[_]]. I’ve tried playing around with FunctorK, but I can’t quite get it to work since I don’t actually have an algebra to transform:

type Alg[_[_]]

implicit val algFunctorK: FunctorK[Alg]

def bar(a: Int): Alg[IO] 

def transformed: Alg[Foo] = ???

Anything obvious I’m missing here? 🤔

Benny Thompson
@bennythomps
Jun 20 18:05
what's the best way to get from an OptionT to an EitherT?
Joe Ferris
@jferris
Jun 20 18:49
@bennythomps toRight or toLeft
Fabio Labella
@SystemFw
Jun 20 19:03
That's amazing!! (RankN)
Basavaraj Kalloli
@scalolli
Jun 20 19:17
Hi I have been trying to add some scala check tests to verify semigroup laws for a type which is analogous to scala's Either, but I am unable to compile this:
https://gist.github.com/scalolli/7728581fb1ecba56e44897e49320a766
For the life of me I cannot figure out the compilation error
Mike (stew) O'Connor
@stew
Jun 20 21:04
@scalolli what is the error you get?
Dermot Haughey
@hderms
Jun 20 21:07
is there a way to monadically compose Seq.headOption and a function lifted into Option
uglyfigurine
@uglyfigurine
Jun 20 21:37
:t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
cats calls this ap
Fabio Labella
@SystemFw
Jun 20 22:30

@smarter @tpolecat just saw the actual gist: first off, awesome!

Second, I do have some question regarding syntax (and corresponding semantics). The type is this:

val fmap: [A, B] -> (A => B) => [F[_]] -> F[A] => implicit Functor[F] => F[B]

The first question is whether order of parameters (e.g. the implicit being last) matters or not. I'm assuming yes because of implicit function types?

The second is scoping and precedence of -> vs =>. The thing that confuses me is that F[_] and [A, B] are in different "type parameter lists", so to speak. And I'm confused as to where exactly the forall are.

I.e. I'd expect the type of fmap to be:

fmap :: forall f a b. Functor f => (a -> b) -> (f a -> f b)

whereas the one in the gist looks like

map :: (forall a b. a -> b) -> (forall f. Functor f => f a -> f b)

which shouldn't even compile? (edit: it should compile but it the a and b aren't the same)

Rob Norris
@tpolecat
Jun 20 22:32
Yeah we had to move the functor because the resulting function type was (implicit Functor[F]) => F[A] => F[B] so addOne(Option(2)) wouldn't compile because it wanted the instance first.
So there's still some funny business but it's really promising.
Fabio Labella
@SystemFw
Jun 20 22:32

So there's still some funny business but it's really promising.

It definitely is :)

Rob Norris
@tpolecat
Jun 20 22:33
I showed it to Martin and he was laughing because it was so cool.
Jakub Kozłowski
@kubukoz
Jun 20 22:33
woah
Fabio Labella
@SystemFw
Jun 20 22:39
this doesn't compile
{-# Language RankNTypes #-}

ffmap :: (forall a b. a -> b) -> (forall f. Functor f => f a -> f b)
ffmap f fa = fmap f fa


res = ffmap (+2) $ Just 4
Couldn't match type ‘a’ with ‘b1’
      ‘a’ is a rigid type variable bound by
          a type expected by the context: a -> b1
          at /Users/fabio/.stack/global-project/.stack-work/intero/intero284rwd.hs:7:7
      ‘b1’ is a rigid type variable bound by
           a type expected by the context: a -> b1
           at /Users/fabio/.stack/global-project/.stack-work/intero/intero284rwd.hs:7:7
    Expected type: a -> b1
      Actual type: a -> a
    In the first argument of ‘ffmap’, namely ‘(+ 2)’
    In the expression: ffmap (+ 2)
    In the expression: ffmap (+ 2) $ Just 4
this does
{-# Language RankNTypes #-}

ffmap :: (a -> b) -> (forall f. Functor f => f a -> f b)
ffmap f fa = fmap f fa


res = ffmap (+2) $ Just 4
so perhaps I'm reading the associativity and precedence of -> vs => wrong?
and val fmap: [A, B] -> (A => B) => [F[_]] -> F[A] => implicit Functor[F] => F[B] translates to the latter?
Jakub Kozłowski
@kubukoz
Jun 20 22:44
I'm assuming val x = fmap((s: String) => 3) would be val x: [F[_]] -> F[String] => implicit Functor[F] => F[Int]
Luka Jacobowitz
@LukaJCB
Jun 20 22:45
I think it translates to `forall a b. (a -> b) -> (forall f.
Functor f => f a -> f b)`
Ugh what the hell gitter
forall a b. (a -> b) -> (forall f. Functor f => f a -> f b)
Jakub Kozłowski
@kubukoz
Jun 20 22:46
how about putting type parameters on the val like on a def, plus multiple type parameter lists?
val x[A, B][F[_]]: (A => B) => F[A] => implicit Functor[F] => F[B] or sth like that
Fabio Labella
@SystemFw
Jun 20 22:47
right, so -> binds all the way to the end, just like forall normally would, cool
@kubukoz you need to able to put type parameters in different position to express RankN types though
Jakub Kozłowski
@kubukoz
Jun 20 22:48
probably, yeah
I realized that once I sent the message
Rob Norris
@tpolecat
Jun 20 23:03
I think what I want to write is val fmap: [A, B] (A => B) => [F[_]: Functor] (F[A] => F[B]) = f => fa => fa.map(f) seems like we're mechanically not too far from it. You'd need some kind of heuristic for shoving the context bounds into the "right" place, which I guess would be as late as possible?