How can I create an array with polymorphic data? - purescript

I am trying to do this
data Foo a = Foo a
data FooWrapper = FooWrapper (forall a. Foo a)
foo = [FooWrapper (Foo 0), FooWrapper (Foo "")]
But there is an error
Could not match type
Int
with type
a0

Existential types don't quite work the same in PureScript as they do in Haskell, so usually we use the purescript-exists library for this kind of thing.
The equivalent using Exists would be:
import Data.Exists (Exists(), mkExists)
data Foo a = Foo a
data FooWrapper = FooWrapper (Exists Foo)
foo = [FooWrapper (mkExists (Foo 0)), FooWrapper (mkExists (Foo ""))]
I suppose in this case you probably don't need FooWrapper at all and could just have an array of Exists Foo.

I wanted to know how Phil Freeman's suggested approach works, so I gave it a try. This is a working example of storing a type class instance with its value by using a rank-n type.
module Example where
import Prelude (class Show, Unit, discard, pure, show, unit, ($))
import Effect (Effect)
import Effect.Console (log)
newtype Showable = Showable (forall r. (forall a. Show a => a -> r) -> r)
instance showShowable :: Show Showable where
show (Showable f) = f show
mkShowable :: forall s . Show s => s -> Showable
mkShowable s = Showable (\f -> f s)
showables :: Array Showable
showables = [mkShowable 1, mkShowable "a string", mkShowable { foo : "bar" } ]
main :: Effect Unit
main = do
log $ show showables
pure unit
The newtype is not really necessary for storing, but i wanted to create an instance of Show for the type itself .

Related

How to use type constrains with Exists

data Foo a = Foo a
I can create an array of Exists https://github.com/purescript/purescript-exists
[(mkExists (Foo 0)), (mkExists (Foo "x"))]
How can I use type classes? I want to get ["0", "x"]
getStrings :: Array (Exists Foo) -> Array String
getStrings list = map (runExists get) list
where
get :: forall a. Show a => Foo a -> String
get (Foo a) = show a
No type class instance was found for
Prelude.Show _0
The instance head contains unknown type variables. Consider adding a
type annotation.
One option is to bundle up the show function in your definition of Foo, something like this:
import Prelude
import Data.Exists
data Foo a = Foo a (a -> String)
type FooE = Exists Foo
mkFooE :: forall a. (Show a) => a -> FooE
mkFooE a = mkExists (Foo a show)
getStrings :: Array FooE -> Array String
getStrings = map (runExists get)
where
get :: forall a. Foo a -> String
get (Foo a toString) = toString a
--
items :: Array FooE
items = [mkFooE 0, mkFooE 0.5, mkFooE "test"]
items' :: Array String
items' = getStrings items

How to correctly unwrap `data` inside `data`?

I’m trying to access nested data (Foo.y inside Bar in the example below), but the straightforward approaches for unwrapping Foo inside Bar that come to mind do not work. But how to unwrap it correctly?
Here my data:
module Foo where
import Prelude
data Foo = Foo { y :: Int }
data Bar = Bar { x :: Int
, foo :: Foo }
The following (of course) does not compile, error is Could not match type { y :: Int } with type Foo — just like Bar, Foo needs unwrapping first:
fn1 :: Bar -> Int
fn1 (Bar { x, foo }) = x + foo.y
So I put up my hopes for the following, but alas, compiler says “no” (parentheses around Foo constructor don’t help):
fn2 :: Bar -> Int
fn2 (Bar { x, Foo { y } }) = x + y
fn3 :: Bar -> Int
fn3 (Bar { x, Foo f }) = x + f.y
The following works, using a helper function to do the unwrapping, but there has got to be a better way:
getY (Foo foo) = foo -- helper function
fn4 :: Bar -> Int
fn4 (Bar { x, foo }) = let foo2 = getY foo in
x + foo2.y
So, how do I do nested “unwrap”?
[EDIT]
After an hour or two of trying things out, I came up with this, which works:
fn5 :: Bar -> Int
fn5 (Bar { x, foo = (Foo f) }) = x + f.y
Is this the idiomatic way to do it? Why don’t fn2 and fn3 work?
Functions fn2 and fn3 do not work because the compiler does not know which record field you are referring to (foo). You have to reference record fields by name.
Function fn4 is a perfectly fine solution (although your naming is pretty confusing, getY actually returns the wrapped record inside the Foo constructor, not the y value).
As far as I can tell, fn5 is the shortest possible solution. I would personally prefer a helper function (like in your fourth example):
getY :: Foo -> Int
getY (Foo rec) = rec.y
fn6 :: Bar -> Int
fn6 (Bar { x, foo }) = x + getY foo

Passing a shapeless extensible record to a function (never ending story?

I continue to investigate extensible records as in Passing a Shapeless Extensible Record to a Function (continued): the provided solution works with functions that all takes a parameter that includes at least foo1, foo2, and foo3; that is one can write:
fun1(("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: HNil)
fun1(("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: ("foo4" ->> true) :: HNil)
and so on
And if we can add a second function fun2:
def fun2[L <: HList : HasMyFields](xs: L) = {
val selectors = implicitly[HasMyFields[L]]
import selectors._
xs("foo1").length + xs("foo2") + xs("foo3")
}
So far, so good.
Now, let's assume we have a set of fields foo1, foo2,... And a set of functions fun1, fun2, which take as parameter a record composed with any subset of {foo1, foo2,...}. For example, fun1 could take as parameter a record that contains foo1 and foo3 but not necessarily foo2, fun2 would expects a record with at least foo4 and so on.
Is there a way to avoid to declare as many class like HasMyFields as they are possible combinations (if we have n fields, there are 2**n combinations!)?
This is a lot easier without an additional type class with the new-ish Witness syntax:
import shapeless._, ops.record.Selector, record._, syntax.singleton._
// Uses "foo1" and "foo2" fields; note that we get the appropriate static types.
def fun1[L <: HList](l: L)(implicit
foo1: Selector.Aux[L, Witness.`"foo1"`.T, String],
foo2: Selector.Aux[L, Witness.`"foo2"`.T, Int]
): (String, Double) = (foo1(l), foo2(l))
And then if we have this record:
val rec = ("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: HNil
We get this:
scala> fun1(rec)
res0: (String, Double) = (hello,1.0)
The new syntax allows us to avoid creating witness values separately, so it's pretty easy to just require the Selector instances you need.
Starting with the answer of Travis, I've been able to improve it :
In a first file, I have :
package p2;
import shapeless._, ops.record.Selector, record._, syntax.singleton._
object MyFields {
type wfoo1[L<: HList]=Selector.Aux[L,Witness.`"foo1"`.T, String]
type wfoo2[L<: HList]=Selector.Aux[L,Witness.`"foo2"`.T, Int]
}
and then, elsewhere :
package p1;
import shapeless._, ops.record.Selector, record._, syntax.singleton._
import p2.MyFields._
object testshapeless extends App {
def fun1[L <: HList](l: L)(implicit
foo1: wfoo1[L],
foo2: wfoo2[L]
): (String, Double) = (foo1(l), foo2(l))
val rec = ("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: HNil
println(fun1(rec));
}
The first file can be considered like a schema where I declare the fields that I potentially use in my application and I've just to import it.
That's cool!
Edited on June 30 :
I wonder if we could do better, maybe with a macro :
Would it be possible to write something like :
def fun1[L <:HList] WithSelectors(MyFields)=...
The macro WithSelectors would generate :
(implicit foo1: wfoo1[L], foo2: wfoo2[L] )
Any advice?

Scala equivalent of 'forall a. Set a -> Set a -> Set a'

In haskell I can write a function f where
f :: Set a -> Set a -> Set a
and if I take two sets, s1 & s2 of type Set Int, and do f s1 s2 it would produce something of type Set Int.
In scala however, I cannot write this, because A is some fixed type, which conflicts with
Long.
val x = Set(3L)
val y = Set(4L)
def foo[A](f: (Set[A], Set [A]) => Set [A]) = {
f(x,y)
}
What I really want though is def foo[forall A. A] .... How can I write this?
Edit The motivation is that I'm retrieving the data (x & y) from one source, and the method to call on them from another source. x & y are just some sets containing anything, but known to be the same type.
If I have some properly polymorphic function, I could just pass the x&y in, and intersection (or whatever) would work fine because intersection doesn't care what's in the sets, only that they're ordered. Perhaps I've gone forgotten how to do this in non haskell like ways...
In Scala and in Haskell type of f will be similar (up to an isomorphism):
f :: forall a. Set a -> Set a -> Set a
def f[A]: (Set[A], Set[A]) => Set[A]
Generic type parameters in Scala work exactly in the same way as type variables in Haskell. So I'm not sure why you say that in Scala it is impossible - it is not only possible but it even looks very similar. You can call f with arbitrary sets as arguments, just like you'd do it in Haskell:
f[Int](Set(1, 2), Set(3, 4))
The difference starts when you want to pass a polymorphic function into another function which will be able to use it with arbitrary type. In Haskell it requires higher-rank polymorphism:
foo :: (forall a. Set a -> Set a -> Set a) -> Whatever
foo f = toWhatever $ f (makeSet [1, 2, 3]) (makeSet [4, 5, 6]) // you get the idea
Scala does not have direct equivalent for this in its type system. You need to do a special trick to encode required relationship between types. First, define an additional trait:
trait PolyFunction2[F[_], G[_], H[_]] {
def apply[A](f: F[A], g: G[A]): H[A]
}
Then you need to extend this trait to define polymorphic functions:
def f = new PolyFunction2[Set, Set, Set] {
def apply[A](f: Set[A], g: Set[A]): Set[A] = f ++ g
}
And you need to use this trait to define type parameters:
def foo(f: PolyFunction2[Set, Set, Set]): (Set[Int], Set[String]) =
(f(Set(1, 2), Set(3, 4)), f(Set("a"), Set("b")))
scala> foo(f)
res1: (Set[Int], Set[String]) = (Set(1, 2, 3, 4),Set(a, b))
Of course, this is an ad-hoc implementation, so you better use Shapeless as it is more general.
Here's a polymorphic function that computes the intersection of two sets of any type, using shapeless
import shapeless._
import shapeless.poly._
object intersect extends Poly2 {
implicit def caseSet[A] = at[Set[A], Set[A]] { case (set1, set2) => set1 & set2 }
}
f(Set(3L, 4L), Set(4L, 5L)) // Set(4)
f(Set("foo", "bar", "baz"), Set("bar", "baz", "faz")) // Set("bar", "baz")
Then you can define a method taking any polymorphic function that can operate on two Sets:
def foo[A](a: Set[A], b: Set[A], f: Poly2)(
implicit c: Case2[f.type, Set[A], Set[A]]
) = f(a, b)
f(Set(3L, 4L), Set(4L, 5L), intersect) // Set(4)
f(Set("foo", "bar", "baz"), Set("bar", "baz", "faz"), intersect) // Set("bar", "baz")
That being said, the above is neat, but probably overkill in your case. In pure vanilla scala, you could instead do
def foo[A](a: Set[A], b: Set[A])(f: Function2[Set[A], Set[A], Set[A]]) = f(a, b)
foo(Set(1L, 2L), Set(2L, 3L)){ case (s1, s2) => s1 & s2 } // Set(2)

Scala - Option.getOrElse() "type erasure"?

I am trying to use the Option.getOrElse() method but it returns etiher Any or ScalaObject instead of an instance of the correct class that the Option was parametrized with. I can't find any mention about this problem and it does not seem like it should be there. What am I doing wrong?
class MyClass {
def isOk = true
}
val myVal = Some(new MyClass) // :Option[MyClass]
val check = myVal.getOrElse(false).isOk
Can't call the isOk method because it tries calling it upon Any.
You are trying to call method isOk on base class of MyClass and Boolean (Any).
Try this:
scala> class MyClass(b: Boolean) { def isOk = b }
defined class MyClass
scala> val myVal = Some(new MyClass(true))
myVal: Some[MyClass] = Some(MyClass#35d56bbe)
scala> myVal.map{_.isOk}.getOrElse(false)
res0: Boolean = true
scala> myVal.getOrElse(new MyClass(false)).isOk
res1: Boolean = true
Works as designed. This expression:
myVal.getOrElse(false)
returns either unwrapped MyClass instance or (if Option is actually None) - false. The only common type of MyClass and Boolean is... Any. And this is what you are seeing.
In order for this to work you must return something compatible with MyClass from getOrElse():
myVal.getOrElse(new MyClass).isOk
Or maybe you want to implement null-object pattern:
object MyClass {
val Empty = new MyClass
}
myVal.getOrElse(MyClass.Empty).isOk
You are applying getOrElse in a Option[MyClass] with Boolean, so, their common superclass is Any.
You should pattern match:
val check = myVal match {
case Some(c) => c.isOk
case None => false
}
You are calling getOrElse on an Option[MyClass]. You're passing a Boolean as a parameter to getOrElse. What happens is that Scala is translating the option to an Option[Any], because Any is the most specific common type of MyClass and Boolean.
Pass a MyClass (or a subclass of MyClass) to getOrElse instead of false.
Because your getOrElse could return false, the common type for MyClass and false is Any.
Jhonny Everson is right. Pattern matching is the answer. In this case, the pattern in his answer is equivalent to exists
scala> Some(new MyClass) :: None :: Nil map(_.exists(_.isOK))
res12: List[Boolean] = List(true, false)
So you've got an Option[A], and a function A => B, and a default B for when the Optional value is None, and you want to end up with a B. (In your case, A is MyClass and B is Boolean).
Being a Haskeller, the first thing I think to do is hoogle. Recall that in Haskell, Option is called Maybe. So we hoogle Maybe a -> (a -> b) -> b -> b, and the top hit is maybe :: b -> (a -> b) -> Maybe a -> b, which does exactly what we want.
data MyClass = MyClass { isOK :: Bool }
newMyClass = MyClass { isOK = true }
myVal = newMyClass
check = maybe False isOK myVal
Well that's well and good, but what about Scala? Well, the Scala equivalent to hoogle is Scalex. I searched Scalex for Option[A] => B => (A => B) => B, but to no avail. So instead, let's check out how the maybe function was implemented in Haskell. You can find the source by following the appropriate links from hoogle.
maybe :: b -> (a -> b) -> Maybe a -> b
maybe n _ Nothing = n
maybe _ f (Just x) = f x
Seems easy enough to translate into Scala
def option[A, B](opt: Option[A])(n: B)(f: A => B) = opt match {
case None => n
case Some(x) => f(x)
}
This can then be used like so:
val check = option(myVal)(false)(_.isOK)
You'll have to ask people more expert in Scala than I if you want to do this with less currying or by pimping the Option class, but notice how this basically boils down to the pattern matching that Jhonny Everson suggested.