Sequence-like Function in Scala - scala

Given a List[Either[A,B]], I could use sequence in Haskell to extract either the entire List of Right[B]s, or Left[A].
Prelude> sequence [Left "bad", Right 555]
Left "bad"
Prelude> sequence [Right 4534, Right 555]
Right [4534,555]
I'm not sure if this method fits the definition of sequence, but it's a narrow function for dealing with List[Either[A,B]] => Either[A, List[B]].
scala> def f[A, B](es: List[Either[A, B]]): Either[A, List[B]] = es match {
| case Right(x) :: xs => f(xs).right.map(y => x :: y)
| case Nil => Right(Nil)
| case left # Left(_) :: _ => left
| }
But I'm getting this error that I don't understand.
<console>:10: error: type mismatch;
found : scala.collection.immutable.::[Either[?A3,?B3]] where type ?B3 <: B (this is a GADT skolem), type ?A3 <: A (this is a GADT skolem)
required: Either[A,List[B]]
case left # Left(_) :: _ => left
^
What am I doing wrong here?

The error message is saying that the type of left is Either[A, B] but the expected type of f is Either[A, List[B]].
You'll need to deconstruct Left in the case and then reconstruct it in the expression. It seems silly but you have the remember that the Left(x) in the branch is tagged with a different type from the one you want.
| case Left(x) :: _ => Left(x)
Haskell would give you a similar error:
f :: Either a b -> Either a [b]
f l#(Left x) = l
Couldn't match type ‘b’ with ‘[b]’
‘b’ is a rigid type variable bound by
the type signature for f :: Either a b -> Either a [b]
at /Users/Jake/Code/Haskell/L.hs:3:6
Expected type: Either a [b]
Actual type: Either a b
Relevant bindings include
l :: Either a b (bound at /Users/Jake/Code/Haskell/L.hs:4:3)
f :: Either a b -> Either a [b]
(bound at /Users/Jake/Code/Haskell/L.hs:4:1)
In the expression: l
In an equation for ‘f’: f l#(Left x) = l

Related

How to implement a recursive Scala 3 function that returns a recursive match type?

I fail to implement a function that returns a recursive match type. As an example, I took the tuple Append type from the std lib and tried to implement a simple append function.
// Tuple append match type, copied from std lib
type Append[X <: Tuple, Y] <: Tuple = X match {
case EmptyTuple => Y *: EmptyTuple
case x *: xs => x *: Append[xs, Y]
}
// Types work just fine
val x: Append[(String, Int), Long] = ("", 1, 2L)
// My simple function implementation that does not compile
def append[X <: Tuple, Y](x: X, y: Y): Append[X, Y] = x match
case _: EmptyTuple => y *: EmptyTuple
case x *: xs => x *: append(xs, y)
[E007] Type Mismatch Error:
case _: EmptyTuple => y *: EmptyTuple
^^^^^^^^^^^^^^^
Found: Y *: EmptyTuple.type
Required: Append[X, Y]
where: X is a type in method append with bounds <: Tuple
Note: a match type could not be fully reduced:
trying to reduce Append[X, Y]
failed since selector X
does not match case EmptyTuple => Y *: EmptyTuple
and cannot be shown to be disjoint from it either.
Therefore, reduction cannot advance to the remaining case
case x *: xs => x *: Append[xs, Y]
longer explanation available when compiling with `-explain`
[E007] Type Mismatch Error:
case x *: xs => x *: append(xs, y)
^^^^^^^^^^^^^^^^^^
Found: Any *: Append[Tuple, Y]
Required: Append[X, Y]
where: X is a type in method append with bounds <: Tuple
Note: a match type could not be fully reduced:
trying to reduce Append[Tuple, Y]
failed since selector Tuple
does not match case EmptyTuple => Y *: EmptyTuple
and cannot be shown to be disjoint from it either.
Therefore, reduction cannot advance to the remaining case
case x *: xs => x *: Append[xs, Y]
longer explanation available when compiling with `-explain`
Scastie
The compiler is very fussy when it comes to returning match types. Your second case needs a small modification to get it to work without the cast (Scastie):
def append[X <: Tuple, Y](x: X, y: Y): Append[X, Y] = x.match {
case _: EmptyTuple => y *: EmptyTuple
case (x *: xs): (x *: xs) => x *: append(xs, y)
}
Without the : (x *: xs), the compiler doesn't understand that your function's second case corresponds with the second case of the match type. Perhaps in the future it'll be smarter.
A cast in the append function did the trick. I couldn't manage to inline it, but this is sufficient for now.
// Tuple append match type, copied from std lib
type Append[X <: Tuple, Y] <: Tuple = X match {
case EmptyTuple => Y *: EmptyTuple
case x *: xs => x *: Append[xs, Y]
}
// Types work just fine
val x: Append[(String, Int), Long] = ("", 1, 2L)
// Function now compiles and succeeds at runtime
def append[X <: Tuple, Y](x: X, y: Y): Append[X, Y] = x.match {
case _: EmptyTuple => y *: EmptyTuple
case x *: xs => x *: append(xs, y)
}.asInstanceOf[Append[X, Y]]
append((1, 2), 3)
Scastie

No type class instance was found, the instance head contains unknown type variables

Well, just simplified as possible:
There is a function that takes functor and does whatever
sToInt :: ∀ a s. Functor s => s a -> Int
sToInt val = unsafeCoerce val
Usage of this function with functor S which param (v) is functor too.
-- declare date type S that is functor
data S (v :: Type -> Type) a = S (v a)
instance functorS :: Functor v => Functor (S v) where
map f (S a) = S (map f a)
sV :: ∀ v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV -- get the error here
No type class instance was found for
Data.Functor.Functor t2
The instance head contains unknown type variables. Consider adding a type annotation.
while applying a function sToInt
of type Functor t0 => t0 t1 -> Int
to argument sV
while checking that expression sToInt sV
has type Int
in value declaration sss
where t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
So it doesn't like S Functor instance has v param Functor constraint, I wonder why getting this error and how to fix it for this case.
This doesn't have to do with v or with the specific shape of S. Try this instead:
sV :: forall f a. Functor f => f a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
You get a similar error.
Or here's an even more simplified version:
sV :: forall a. a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
Again, same error.
The problem is that sToInt must get a Functor instance as a parameter (that's what the Functor s => bit in its type signature says), and in order to pick which Functor instance to pass, the compiler needs to know the type of the value. Like, if it's Maybe a, it will pass the Functor Maybe instance, and if it's Array a, it will pass the Functor Array instance, and so on.
Usually the type can be inferred from the context. For example when you say map show [1,2,3], the compiler knows that map should come from Functor Array, because [1,2,3] :: Array Int.
But in your case there is nowhere to get that information: sV can return S v for any v, and sToInt can also take any functor type. There is nothing to tell the compiler what the type should be.
And the way to fix this is obvious: if there is no context information for the compiler to get the type from, you have to tell it what the type is yourself:
sss :: Int
sss = sToInt (sV :: S Maybe _)
This will be enough for the compiler to know that v ~ Maybe, and it will be able to construct a Functor (S Maybe) instance and pass it to sToInt.
Alternatively, if you want the consumer of sss to decide what v is, you can add an extra dummy parameter to capture the type, and require that the consumer pass in a Functor v instance:
sss :: forall v. Functor v => FProxy v -> Int
sss _ = sToInt (sV :: S v _)
ddd :: Int
ddd = sss (FProxy :: FProxy Maybe)
In Haskell you can do this with visible type applications instead of FProxy, but PureScript, sadly, doesn't support that yet.
Even more alternatively, if sToInt doesn't actually care for a Functor instance, you can remove that constraint from it, and everything will work as-is:
sToInt :: forall s a. s a -> Int
sToInt a = unsafeCoerce a
sV :: forall v a. S v a
sV = unsafeCoerce 1
sss :: Int
sss = sToInt sV
This works because PureScript allows for ambiguous (aka "unknown") types to exist as long as they're not used for selecting instances.

standard specialization of Either where type of Left and Right is the same

Is there a standard specialization of Either in Haskell or Scala that makes the types contained in the Left and Right the same type?
In Haskell, I want something like this:
data SpecializedEither a = Left a | Right a
This might also be considered a slight generalization of Maybe that makes Nothing hold a value.
edit: Ganesh raises a very good point that a Monad instance can't be defined for this type. Is there a better way to do what I am trying to do?
There's a standard Monad instance on ((,) e) so long as e is a Monoid
instance Monoid e => Monad ((,) e) where
return a = (mempty, a)
(e1, a) >>= f = let (e2, b) = f a in (e1 <> e2, b)
Since Either a a and (Bool, a) are isomorphic (in two ways), we get a Monad instance as soon as we pick a Monoid for Bool. There are two (really four, see comments) such Monoids, the "and" type and the "or" type. Essentially, this choice ends up deciding as to whether the Left or Right side of your either is "default". If Right is default (and thus Left overrides it) then we get
data Either1 a = Left1 a | Right1 a
get1 :: Either1 a -> a
get1 (Left1 a) = a
get1 (Right1 a) = a
instance Monad Either1 where
return = Right1
x >>= f = case (x, f (get1 x)) of
(Right1 _, Right1 b) -> Right1 b
(Right1 _, Left1 b) -> Left1 b
(Left1 _, y ) -> Left1 (get1 y)
How about:
type Foo[T] = Either[T, T]
val x: Foo[String] = Right("")
// Foo[String] = Right()

Passing Tuple2 Argument with -> versus ,

Working on a Functional Programming in Scala exercise, I wrote out this function:
def sequenceMap[K, V](ofa: Map[K,F[V]]): F[Map[K, V]] =
ofa.foldLeft(unit(Map[K,V]()))((x, y) => map2(x, y._2)((a, b) =>
(a + (y._1 -> b))))
map2's signature:
def map2[A,B,C](fa: F[A], fb: F[B])(f: (A,B) => C): F[C]
However, when I replaced the last -> with , to make the tuple2, the following compile-time type mismatch occurred:
[error] found : K
[error] required: (K, V)
[error] ofa.foldLeft(unit(Map[K,V]()))((x, y) =>
map2(x, y._2)((a, b) => (a + (y._1 , b))))
Why is this occurring? Is it possible to use a comma and still avoid this compile-time problem?
When you write f(a, b) you're applying the 2-ary function f to the 2 arguments a and b. To apply f to the Tuple2 (a, b) you need to add another set of parens: f((a, b)).

Scala for-comprehension type inference

The next code
def f(chars: List[Char]): List[List[Char]] = chars match {
case Nil => List(Nil)
case x :: xs => for {
v <- f(xs)
} yield List(x) :: v
}
gives the error message
- type mismatch; found : List[List[Any]] required: List[List[Char]]
Please help me understand why 'for' chooses the most general Any instead of Char here? What topic in language spec should I read? Thanks.
The result, you are yielding is a mix of List[List[List[Char]]] and List[List[Char]]. Scala upcasts that to List[List[Any]]. For your case either of the following will do the job:
scala> def f(chars: List[Char]): List[List[Char]] = chars match {
| case Nil => List(Nil)
| case x :: xs => for {
| v <- f(xs)
| } yield x :: v
| }
f: (chars: List[Char])List[List[Char]]
scala> def f(chars: List[Char]): List[List[Char]] = chars match {
| case Nil => List(Nil)
| case x :: xs => for {
| v <- f(xs)
| } yield List(x) ++ v
| }
f: (chars: List[Char])List[List[Char]]
The problem is List(x) -- it needs to be x.
First, v iterates over the results of f(xs), and f returns List[List[Char]]. That means the result will be List[X], where X is the type returned by yield.
The type of v is List[Char], since it is iterating over the contents of f(xs). So we have to figure out the type of List(x) :: v, which is prepending a List[Char] on a List[Char]. It is not concatenating them: it is adding a list to a list containing only characters. The resulting list will have both Char and List[Char] in it.
Since the only type that satisfy both is Any, then X will be Any and the result of the for-comprehension List[Any].