Skip to content
This repository has been archived by the owner on Dec 15, 2020. It is now read-only.

part-2.4, 'Representable Functors' #51

Merged
merged 1 commit into from
Feb 2, 2018

Conversation

Zelenya
Copy link
Contributor

@Zelenya Zelenya commented Jan 28, 2018

Fixes #22

@Zelenya Zelenya force-pushed the part-2.4-representable-functors branch from c47f5d3 to 6ba75ec Compare January 28, 2018 15:31
Copy link
Contributor

@kailuowang kailuowang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beautiful! Thanks!

@SystemFw
Copy link
Contributor

There's quite a lot to review on this :)
I'll try to get to it asap.

P.S. @Zelenya Thanks a lot for all this effort! 😄

```
```scala
`C(A, X)` => `C(A, Y)`
```
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above is pseudo haskell, so I'm not sure how to translate it. but it should probably be C[A, X]. The way you've written that's a specific type which happens to be called C(A, X) (the A and X are part of the name)

f ∘ h :: a -> y
```
```scala
val `f ∘ h`: A => Y
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scala code is not the same as the haskell above:
in the haskell snippet a and y are universally quantified, whereas in the scala code they are concrete types called A and Y.
It should be

def `f ∘ h`[A, Y] : A =>  Y

```
```tut:silent
case class Reader[A, X](run: A => X)
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking the haskell code is using a type synonym, not a newtype, so the translation is a also a type synonym, not a case class. Not sure this is worth changing though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've shamefully copy-pasted it from the 1.10 and not noticed the difference.
It was newtype Reader e a = Reader (e -> a)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, I don't really mind too much which way you go, just wanted to point out the discrepancy :)

new Functor[({type T[X] = Reader[A, X]})#T] {
def fmap[X, B](f: X => B)(h: Reader[A, X])
: Reader[A, B] =
Reader(x => f(h.run(x)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here re: newtype

```
```tut:silent
case class Op[A, X](f: X => A)
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here re: newtype

αx :: C(a, x) -> F x
```
```scala
val αx: `C(A, X)` => F[X]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A and X are type variables in the haskell code, in yours C(A, X) is a concrete type named C(A, X) (there the X has no connection with the latter X), and X is a concrete type called X

```
```scala
def alpha[X]: (A => X) => F[X]
```
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is incorrect. The haskell version has type

alpha :: forall a. (forall x. (a -> x) -> F x)

so it's a natural transformation between (-> a) and F. The scala code is a normal function where X is a type parameter, F is fixed (correctly), and A is fixed (incorrectly). And the returned type is not polymorphic enough (it's not first class polymorphic).

To encode this you need a type such as the one in cats:

trait FunctionK[G[_], H[_]] {
  def apply[A](ga: G[A]): H[A]
}

and alpha becomes

def alpha[A]: FunctionK[A => ?, F]

```scala
fmap(f)(alpha(h)) == alpha(f compose h)
```
................
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code for the two laws will probably change once you apply the change above

```
```scala
def beta[X]: F[X] => (A => X)
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment re: natural transformation applies to beta

```tut:silent
def alpha[X]: (Int => X) => List[X] =
h => List(12).map(h)
```
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, this should be

def alpha: FunctionK[Int => ?, List] = ...and so on

```
```scala
def beta[X]: List[X] => (Int => X)
```
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same:

def beta: FunctionK[List, Int => ?]

h: () => A,
t: () => Stream[A]
) extends Stream[A]
```
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a general thing about datatypes, but in scala one would never have a trait with only one subclass, just go with

case class Stream[X](h:  () => X, t: () => Stream[X])

```
```tut:silent
trait Representable[F[_]] {
type Rep[F[_]]
Copy link
Contributor

@SystemFw SystemFw Jan 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be lower kinded, type Rep
Type families and abstract types work differently

type Rep[F[_]]

def tabulate[X](f: Rep[F] => X): F[X]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rep


def index[X]: F[X] => Rep[F] => X
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rep

else index(bs())(n - 1)
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will become:

 implicit def streamRepresentable: Representable[SStream]{type Rep = Int} = 
      new Representable[SStream] {
        type Rep = Int

        def tabulate[X](f: Rep => X)
            : SStream[X] =
          SStream[X](
            () => f(0),
            () => tabulate(f compose (_ + 1)))

        def index[X]
            : SStream[X] => Rep => X =
          s => n =>  {
            if (n == 0) s.h()
            else index(s.t())(n - 1)
          }

      }
  }

Copy link
Contributor

@SystemFw SystemFw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the spam, didn't realise I wasn't doing it all at once in a review

@Zelenya Zelenya force-pushed the part-2.4-representable-functors branch 3 times, most recently from db6c332 to 98fa2e8 Compare February 1, 2018 19:44
@Zelenya
Copy link
Contributor Author

Zelenya commented Feb 1, 2018

@SystemFw Ready for the round 2.

Copy link
Contributor

@SystemFw SystemFw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of small changes left! Thanks a lot for your continued effort :)

αx :: C(a, x) -> F x
```
```scala
def α[X]: C[A, X] => F[X]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing an A type parameter

In order to make a universal transformation,
another type needs to be introduced.
FunctionK (~>) transforms values from one
first-order-kinded type into another:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first-order-kinded type is confusing. Also, the description would also apply to
def foo[F[_], G[_], A](fa: F[A]): G[A], which isn't a natural transformation: it's really the higher rank polymorphism that matters here. Personally I'd just remove the second paragraph and link at the docs for FunctionK

index (Cons b bs) n = if n == 0 then b else index bs (n - 1)
```
```tut:silent
implicit def streamRepresentable =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add the explicit type here, for two reasons:

  • it's good practice to always annotate implicits
  • it's someone decides to add a signature of Representable[Stream] the code will compile, but be broken as the refinement is lost

@Zelenya Zelenya force-pushed the part-2.4-representable-functors branch from 98fa2e8 to 20d632c Compare February 2, 2018 07:25
```
```tut:silent
implicit def streamRepresentable
: Representable[Stream] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I swear this is the last one 😂
The type of this is Representable[Stream]{type Rep = Int}, you want to keep the Rep = Int refinement

@Zelenya Zelenya force-pushed the part-2.4-representable-functors branch from 20d632c to 27d5fb3 Compare February 2, 2018 11:18
@Zelenya Zelenya force-pushed the part-2.4-representable-functors branch from 27d5fb3 to a41bd79 Compare February 2, 2018 11:20
@Zelenya
Copy link
Contributor Author

Zelenya commented Feb 2, 2018

@SystemFw final round? 😄

Copy link
Contributor

@SystemFw SystemFw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 🎉

Thank you so much! Sorry for the picky review

@SystemFw SystemFw merged commit 0036bf9 into typelevel:master Feb 2, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants