Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Fabio Labella
@SystemFw
:open_mouth:
I need to see how that behaves
Miles Sabin
@milessabin
Yeah, it's not pretty.
I think it's impossible to eliminate the import which means the ergonomics are pretty poor.
Fabio Labella
@SystemFw
one of the issues I've encountered with my experiments is that it would mess the Monad search

do you mean this?

import pack.unpack

Miles Sabin
@milessabin
Yup.
Fabio Labella
@SystemFw
I mean
the experience right now is
.flatMap { case (a,b) =>
   implicit val a_ = a
   implicit val b_ = b
   body[IO] 
}
so a single import doesn't strike me as "pretty poor"
Miles Sabin
@milessabin
YMMV ;-)
Fabio Labella
@SystemFw
I'm more concerned that it works for a specific typeclass
rather than a product of them
although that could be adapted
thanks a lot, I'll play with it
Miles Sabin
@milessabin
Yes, the example gives you F[A], F[B], F[C] ... for a given F.
Fabio Labella
@SystemFw
I tried doing it at kind *, which destroyed everything :)
Miles Sabin
@milessabin
You want F[T], G[T], H[T] ... for a given T.
Fabio Labella
@SystemFw
well, ideally I want A, B, C given A :: B :: C:: HNil
but that implicit def[A](machinery): A cause ambiguous implicits
Miles Sabin
@milessabin
Sure.
Fabio Labella
@SystemFw
and using LowPriority cause either no effect (if it's not the first in the implicit parameter list), or compiler crash
Miles Sabin
@milessabin
I don't there are any nice solutions in Scala 2.
You might do better in Dotty, but I haven't investigated.
Fabio Labella
@SystemFw
I tried implicit def a[A <: Marker](....) but still ambiguous
yeah, roughly what I feared
well, thanks :)
Miles Sabin
@milessabin
It might be an idea to try and make something work in dotty and then see if you can crowbar it back into Scala 2.
It definitely helps to have a working example.
FWIW, if you squint at this in the right way it looks a bit like some of the encodings of Eff type things.
Miles Sabin
@milessabin
In dotty you can probably simplify your example with this new construct: https://dotty.epfl.ch/docs/reference/contextual/givens.html#pattern-bound-given-instances
Fabio Labella
@SystemFw

way it looks a bit like some of the encodings of Eff type things.

yeah, the simplest part of the Eff machinery

that's normally done with type families, so I want to look at match types

https://dotty.epfl.ch/docs/reference/contextual/givens.html#pattern-bound-given-instances

this improves the situation, but I think the code above is useful when you consider that there is a mix of Resource, Stream and IO. So I tend to make one big Resource computation with everything I need and Stream.resource (or IO.use) that, which saves you having to write a big for full of Stream.resource)

Markus Appel
@markusa380
Quick question, is there an implicit method to convert a case class to a record?
Something to abbreviate LabelledGeneric[A].to(a) to a.lgen or a.record or something?
Dmytro Mitin
@DmytroMitin
@markusa380
import shapeless.syntax.std.product._
a.toRecord
Markus Appel
@markusa380
@DmytroMitin Thx!
Travis
@OleTraveler
I have a working 2.13 library which I am trying to cross compile to 2.12. However, I am getting this error: flip is not a member of B :: shapeless.HNil =:= L. Any quick thoughts on what might be the issue? The code looks liks so: val f2: L => A = h => f(witness.flip(h).head)
Travis
@OleTraveler
  def xmap[A: Manifest, B](f: B => A, g: A => B, validation: ValidationOp[A]*)(
    implicit isEqual: (B :: HNil) =:= L
  ): KvpWrappedHList[K, ALG, A, L, LL] = {
    type T = B :: HNil
    val witness = implicitly[(B :: HNil) =:= L]
    val f2: L => A = h => f(witness.flip(h).head)
    val g2: A => L = a => witness(g(a) :: HNil)
    hListXmap[A](f2, g2, validation.toList: _*)
  }
Travis
@OleTraveler
I found a workaround, I just used 2 implicit params, one for each witness.
Lawrence Carvalho
@lacarvalho91

hey all, how would i go about trying and find an element in a record (where the keys are symbols) by key just given a string? returning an option that is none if that string does not exist as a key in the record

i've seen theres the Keys type class, so i can lookup keys in there after converting to a list or something but i'd like to lookup the key then return the value if that key exists

the main thing here is that at runtime i just have a string to use for the lookup

i've seen ToMap as well, but i don't want to lose the type of the specific value that the lookup finds (if any), i'm hoping i can then just fold on the value (since the type of it would be one of the possible types of the record values)

so i guess something like lookup a record key by string, returning a Some of the value as a coproduct of the record value types or None

Dmytro Mitin
@DmytroMitin

@lacarvalho91 You can try to use com.github.dmytromitin.auxify.shapeless.StringToSymbol

def get[L <: HList, S <: String with Singleton, K <: Symbol](l: L, k: S)(implicit
  stringToSymbol: StringToSymbol.Aux[S, K],
  selector: Selector[L, K]
) = selector(l)

val r: Record.`'a -> Int, 'b -> String`.T = 'a ->> 1 :: 'b ->> "abc" :: HNil

get(r, "b") // "abc"
get(r, "c") // doesn't compile

https://scastie.scala-lang.org/0X4je43JT0exS3PUzYV0KA
Or com.github.dmytromitin.auxify.shapeless.LabelledGeneric https://github.com/DmytroMitin/AUXify#using-auxify-shapeless
I guess in Shapeless master shapeless.LabelledGeneric is already String-based.

Lawrence Carvalho
@lacarvalho91

@DmytroMitin thanks so much for the info! Think the main problem is the string i want to use for the lookup isn't known at compile time.

I've got a bit further but now i'm having problems with some Coproduct folds I've defined, if I define the Folder instances manually by just calling the Folder summoner then my project compiles but throws uninitialised field errors at runtime. But if i don't define them myself then the project doesn't compile. I assume theres a problem with the case I have defined in the poly.

What i'm trying to do with this poly is transform each tagged element in my record to a tuple of String -> Coproduct(value), so that I can go from my record => Map[String, CoproductOfTypesInHlist], a bit like using a ToCoproductTraversable but i want the keys of the fields in the record to be converted to strings. The values of the fields in my record type are all Store[Id, K, T], the keys of the fields in the record are all string singleton types.

My current Poly looks like this:

object toStringKeyValue extends Poly1 {
  implicit def caseField[K, K1, T1, C <: Coproduct](
      implicit wk: Witness.Aux[K1],
      inj: Inject[C, Store[cats.Id, K, T1]]
  ) =
    at[FieldType[K1, Store[cats.Id, K, T1]]] { i =>
      wk.value.toString() -> Coproduct[C](getFieldValue(i))
    }

  def getFieldValue[K, V](value: FieldType[K, V]): V = value
}

At the point that the concrete record is created, the compiler knows that all the values of the fields in the record are Stores (where each field in the record is a store parameterised with different types)

is this achievable? i feel like i'm probably going down the wrong path :D

Lawrence Carvalho
@lacarvalho91
i created concrete cases in my poly for each type and it worked, then i started making it generic again one bit at a time and the problem seems to be with parameterising the coproduct type in that caseField, as soon as I do that it stops working. It was working with every other part of that poly being generic. As soon as I parameterise the coproduct type (as well as passing the paramterised coproduct type to the first Inject type parameter) thats when it fails to compile :(
Dmytro Mitin
@DmytroMitin
@lacarvalho91 see https://scastie.scala-lang.org/34uAQFTHQWmnLbax38sebQ
  object toStringKeyValue extends Poly2 {
    implicit def cnil[K <: Symbol, V](implicit
                                                                      witness: Witness.Aux[K],
                                                                      inject: Inject[V :+: CNil, V],
                                                                     ):
    Case.Aux[Map[String, CNil], FieldType[K, V], Map[String, V :+: CNil]] =
      at((_, v) => Map(witness.value.name -> inject(v)))

    implicit def cse[K <: Symbol, V, C <: Coproduct, C1 <: Coproduct](implicit
                                                                      witness: Witness.Aux[K],
                                                                      extend: ExtendRightIfAbsent.Aux[C, V, C1],
                                                                      inject: Inject[C1, V],
                                                                     ):
    Case.Aux[Map[String, C], FieldType[K, V], Map[String, C1]] =
      at((m, v) => (m.view.mapValues(extend(_)) + (witness.value.name -> inject(v))).toMap)
  }

  val r: Record.`'a -> Int, 'b -> String`.T = 'a ->> 1 :: 'b ->> "abc" :: HNil

  r.foldLeft(Map.empty[String, CNil])(toStringKeyValue) // Map(a -> Inl(1), b -> Inr(Inl(abc)))
Lawrence Carvalho
@lacarvalho91
oh that looks cool! will give it a go. Thanks a lot for your help!
Leif Warner
@LeifW
Anyone have an opinion on which would be better (lower runtime cost, hopefully) between refined Size vs shapeless Sized?
Just thinking to assert e.g. a byte array has 8 elements (so I know it can represent a Long).
Gabriel Volpe
@gvolpe
I guess both are fine, and refined is built on top of shapeless FWIW
Dmytro Mitin
@DmytroMitin
@LeifW It's a little weird to compare performance of eu.timepit.refined.collection.Size vs. shapeless.Sized because they provide different functionality. The former works at compile time while the latter works at compile time only for literals
import eu.timepit.refined.api.Refined
import eu.timepit.refined.collection.Size
import eu.timepit.refined.generic.Equal
import shapeless.Sized
import shapeless.nat._
import eu.timepit.refined.auto._

  val arr: Sized[Array[Byte], _8] = Sized[Array](0, 1, 2, 3, 4, 5, 6, 7) // compiles
//  val arr1: Sized[Array[Byte], _8] = Sized[Array](0, 1, 2, 3, 4, 5, 6) // type mismatch, found: Sized[Array[Int],_7], required: Sized[Array[Byte],_8]

  val str: String Refined Size[Equal[8]] = "01234567" // compiles
//  val str1: String Refined Size[Equal[8]] = "0123456" //Predicate taking size(0123456) = 7 failed: Predicate failed: (7 == 8)

//  val arr2: Array[Byte] Refined Size[Equal[8]] = Array(0, 1, 2, 3, 4, 5, 6, 7) //compile-time refinement only works with literals
//  val arr3: Array[Byte] Refined Size[Equal[8]] = Array(0, 1, 2, 3, 4, 5, 6) //compile-time refinement only works with literals
@gvolpe refined mostly uses its own macros and type classes and sometimes uses Shapeless (Witness, @@, nat._...). eu.timepit.refined.collection.Size isn't built on top of shapeless.Sized.