PureScript - How to Add or Subtract NewTypes - purescript

Consider this intuitive example, where one attempts to use the (+) operator on two NewTypes derived from Number:
module Main where
import Prelude (Unit, (+))
import Effect (Effect)
import Effect.Console (logShow)
newtype Balance = Balance Number
a :: Balance
a = Balance 7.18
b :: Balance
b = Balance 16.50
c :: Balance
c = a + b
main :: Effect Unit
main = do
logShow c
However, attempting this operation produces the following error:
No type class instance was found for
Data.Semiring.Semiring Balance
while applying a function add
of type Semiring t0 => t0 -> t0 -> t0
to argument a
while inferring the type of add a
in value declaration c
where t0 is an unknown type
So, in essense, the question is
How do you operate on newtypes as though they were the type they were derived from?
So ideally this solution would also work when concatenating two values of a new type based on string, or comparing two values of a new type based on boolean, etc.

newtypes do not inherit the typeclass implementations of the underlying type. You either have to implement it manually, or if it's supported, derive the instance. In this case, PureScript supports deriving addition (Data.Semiring):
newtype Balance = Balance Number
derive newtype instance Semiring Balance
Full code (you can copy paste it into https://try.purescript.org/ to try):
module Main where
import Prelude (Unit, (+))
import Data.Semiring (class Semiring)
import Data.Show (class Show)
import Effect (Effect)
import Effect.Console (logShow)
newtype Balance = Balance Number
derive newtype instance Semiring Balance
derive newtype instance Show Balance
main :: Effect Unit
main = do
logShow ((Balance 7.18) + (Balance 16.50))
Output:
23.68

Related

Could not match kind: KindsDoNotUnify error

This is a strange error I encountered while in practice, the thing is that there is a data type, that has an alias (defined in another module) and deriving newtype instance for the type the uses this alias type leads to the compiler error.
So, I tried to narrow it down the case, it requires two small modules to be reproduced:
Module A, which uses TAlias from Module B to declare newtype and derive Newtype instance:
module A where
import B (TAlias)
import Data.Newtype (class Newtype)
data M a = M a
-- define a type that uses alas type
newtype NewA a = NewA (TAlias (M a))
derive instance Newtype (NewA a) _
Module B, where T and TAlias are defined
module B where
data T :: forall m. m -> Type
data T msg = E
type TAlias :: forall k. k -> Type
type TAlias msg =
T msg -- here is is the error
In the last line of the module B the compiler (Purescript 0.14.4) gives an error:
Could not match kind
Type
with kind
k
while checking that type M a
has kind k
while inferring the kind of T #k (M a)
while inferring the kind of Newtype (NewA a) (T #k (M a))
in type class instance
Data.Newtype.Newtype (NewA a)
(T #k (M a))
PureScript(KindsDoNotUnify)
So I wonder what is the reason for the error? How it can be fixed to allow deriving Newtype in such a case.

how to normalize a `scala.reflect.api.Types.Type`

How to implement the function normalize(type: Type): Type such that:
A =:= B if and only if normalize(A) == normalize(B) and normalize(A).hashCode == normalize(B).hashCode.
In other words, normalize must return equal results for all equivalent Type instances; and not equal nor equivalent results for all pair of non equivalent inputs.
There is a deprecated method called normalize in the TypeApi, but it does not the same.
In my particular case I only need to normalize types that represent a class or a trait (tpe.typeSymbol.isClass == true).
Edit 1: The fist comment suggests that such a function might not be possible to implement in general. But perhaps it is possible if we add another constraint:
B is obtained by navigating from A.
In the next example fooType would be A, and nextAppliedType would be B:
import scala.reflect.runtime.universe._
sealed trait Foo[V]
case class FooImpl[V](next: Foo[V]) extends Foo[V]
scala> val fooType = typeOf[Foo[Int]]
val fooType: reflect.runtime.universe.Type = Foo[Int]
scala> val nextType = fooType.typeSymbol.asClass.knownDirectSubclasses.iterator.next().asClass.primaryConstructor.typeSignature.paramLists(0)(0).typeSignature
val nextType: reflect.runtime.universe.Type = Foo[V]
scala> val nextAppliedType = appliedType(nextType.typeConstructor, fooType.typeArgs)
val nextAppliedType: reflect.runtime.universe.Type = Foo[Int]
scala> println(fooType =:= nextAppliedType)
true
scala> println(fooType == nextAppliedType)
false
Inspecting the Type instances with showRaw shows why they are not equal (at least when Foo and FooImpl are members of an object, in this example, the jsfacile.test.RecursionTest object):
scala> showRaw(fooType)
val res2: String = TypeRef(SingleType(SingleType(SingleType(ThisType(<root>), jsfacile), jsfacile.test), jsfacile.test.RecursionTest), jsfacile.test.RecursionTest.Foo, List(TypeRef(ThisType(scala), scala.Int, List())))
scala> showRaw(nextAppliedType)
val res3: String = TypeRef(ThisType(jsfacile.test.RecursionTest), jsfacile.test.RecursionTest.Foo, List(TypeRef(ThisType(scala), scala.Int, List())))
The reason I need this is difficult to explain. Let's try:
I am developing this JSON library which works fine except when there is a recursive type reference. For example:
sealed trait Foo[V]
case class FooImpl[V](next: Foo[V]) extends Foo[V]
That happens because the parser/appender it uses to parse and format are type classes that are materialized by an implicit macro. And when an implicit parameter is recursive the compiler complains with a divergence error.
I tried to solve that using by-name implicit parameter but it not only didn't solve the recursion problem, but also makes many non recursive algebraic data type to fail.
So, now I am trying to solve this problem by storing the resolved materializations in a map, which also would improve the compilation speed. And that map key is of type Type. So I need to normalize the Type instances, not only to be usable as key of a map, but also to equalize the values generated from them.
If I understood you well, any equivalence class would be fine. There is no preference.
I suspect you didn't. At least "any equivalence class would be fine", "There is no preference" do not sound good. I'll try to elaborate.
In math there is such construction as factorization. If you have a set A and equivalence relation ~ on this set (relation means that for any pair of elements from A we know whether they are related a1 ~ a2 or not, equivalence means symmetricity a1 ~ a2 => a2 ~ a1, reflexivity a ~ a, transitivity a1 ~ a2, a2 ~ a3 => a1 ~ a3) then you can consider the factor-set A/~ whose elements are all equivalence classes A/~ = { [a] | a ∈ A} (the equivalence class
[a] = {b ∈ A | b ~ a}
of an element a is a set consisting of all elements equivalent (i.e. ~-related) to a).
The axiom of choice says that there is a map (function) from A/~ to A i.e. we can select a representative in every equivalence class and in such way form a subset of A (this is true if we accept the axiom of choice, if we don't then it's not clear whether we get a set in such way). But even if we accept the axiom of choice and therefore there is a function A/~ -> A this doesn't mean we can construct such function.
Simple example. Let's consider the set of all real numbers R and the following equivalence relation: two real numbers are equivalent r1 ~ r2 if their difference is a rational number
r2 - r1 = p/q ∈ Q
(p, q≠0 are arbitrary integers). This is an equivalence relation. So it's known that there is a function selecting a single real number from any equivalence class but how to define this function explicitly for a specific input? For example what is the output of this function for the input being the equivalence class of 0 or 1 or π or e or √2 or log 2...?
Similarly, =:= is an equivalence relation on types, so it's known that there is a function normalize (maybe there are even many such functions) selecting a representative in every equivalence class but how to prefer a specific one (how to define or construct the output explicitly for any specific input)?
Regarding your struggle against implicit divergence. It's not necessary that you've selected the best possible approach. Sounds like you're doing some compiler work manually. How do other json libraries solve the issue? For example Circe? Besides by-name implicits => there is also shapeless.Lazy / shapeless.Strict (not equivalent to by-name implicits). If you have specific question about deriving type classes, overcoming implicit divergence maybe you should start a different question about that?
Regarding your approach with HashMap with Type keys. I'm still reminding that we're not supposed to rely on == for Types, correct comparison is =:=. So you should build your HashMap using =:= rather than ==. Search at SO for something like: hashmap custom equals.
Actually I guess your normalize sounds like you want some caching. You should have a type cache. Then if you asked to calculate normalize(typ) you should check whether in the cache there is already a t such that t =:= typ. If so you should return t, otherwise you should add typ to the cache and return typ.
This satisfies your requirement: A =:= B if and only if normalize(A) == normalize(B) (normalize(A).hashCode == normalize(B).hashCode should follow from normalize(A) == normalize(B)).
Regarding transformation of fooType into nextAppliedType try
def normalize(typ: Type): Type = typ match {
case TypeRef(pre, sym, args) =>
internal.typeRef(internal.thisType(pre.typeSymbol), sym, args)
}
Then normalize(fooType) == nextAppliedType should be true.

Questions about a la carte data types

I was reading the original paper about data types a la carte and decided to try to implement the idea in Scala (I know it's already implemented in many functional libraries). Unfortunately I found the original paper is hard to comprehend and I stuck somewhere in the beginning. Then I found another paper that was easier to understand and I managed to rewrite Haskell code from the paper into Scala, you can find it here. However I still struggling to understand a few moments:
A quote from the second paper
Orignal Expr data type
data Expr = Val Int | Add Expr Expr
New type signature:
data Arith e = Val Int | Add e e
For any functor f, its induced recursive datatype, Fix f, is defined as the least fixpoint of f, implemented as follows:
data Fix f = In (f (Fix f))
Now that we have tied the recursive knot of a signature,
Fix Arith is a language equivalent to the original Expr datatype
which allowed integer values and addition.
What does it mean exactly "we have tied the recursive knot of a signature" and what does it mean Fix Arith is a language equivalent to the original Expr ?
The actual type of In is In :: f (Fix f) -> Fix f
If we try to construct a value using In construct and Val 1 variable we'll get the following result:
> :t In(Val 1)
> In(Val 1) :: Fix Arith
Scala encoding of the same data types:
sealed trait Arith[A]
case class Val[A](x: Int) extends Arith[A]
case class Add[A](a: A, b: A) extends Arith[A]
trait Fix[F[_]]
case class In[F[_]](exp: F[Fix[F]]) extends Fix[F]
fold function
The fold function has the following signature and implementation
Haskell:
fold :: Functor f => (f a -> a) -> Fix f -> a
fold f (In t) = f (fmap (fold f) t)
Scala variant I came up with
def fold[F[_] : Functor, A](f: F[A] => A): Fix[F] => A = {
case In(t) =>
val g: F[Fix[F]] => F[A] = implicitly[Functor[F]].lift(fold(f))
f(g(t))
}
The thing that I'm curious about is that in my Scala version function g has the following type F[Fix[F]] => F[A] but the type of variable t after pattern matching is LaCarte$Add with value Add(In(Val(1)),In(Val(2))), how it happens that it's valid to apply function g to LaCarte$Add ? Also, I'd very appreciate if you can help me to understand fold function ?
Quote from the paper:
The first argument of fold is an f-algebra, which provides
the behavior of each constructor associated with a given signature f.
What does it mean exactly “we have tied the ‘recursive knot’ of a signature”?
The original Expr datatype is recursive, referring to itself in its own definition:
data Expr = Val Int | Add Expr Expr
The Arith type “factors out” the recursion by replacing recursive calls with a parameter:
data Arith e = Val Int | Add e e
The original Expr type can have any depth of nesting, which we want to support with Arith as well, but the maximum depth depends on what type we choose for e:
Arith Void can’t be nested: it can only be a literal value (Val n) because we can’t construct an Add, because we can’t obtain a value of type Void (it has no constructors)
Arith (Arith Void) can have one level of nesting: the outer constructor can be an Add, but the inner constructors can only be Lit.
Arith (Arith (Arith Void)) can have two levels
And so on
What Fix Arith gives us is a way to talk about the fixed point Arith (Arith (Arith …)) with no limit on the depth.
This is just like how we can replace a recursive function with a non-recursive function and recover the recursion with the fixed-point combinator:
factorial' :: (Integer -> Integer) -> Integer -> Integer
factorial' recur n = if n <= 1 then 1 else n * recur (n - 1)
factorial :: Integer -> Integer
factorial = fix factorial'
factorial 5 == 120
What does it mean Fix Arith is a language equivalent to the original Expr?
The language (grammar) that Fix Arith represents is equivalent to the language that Expr represents; that is, they’re isomorphic: you can write a pair of total functions Fix Arith -> Expr and Expr -> Fix Arith.
How it happens that it’s valid to apply function g to LaCarte$Add?
I’m not very familiar with Scala, but it looks like Add is a subtype of Arith, so the parameter of g of type F[Fix[F]] can be filled with a value of type Arith[Fix[Arith]] which you get by matching on the In constructor to “unfold” one level of recursion.

Get a newtype'd records underlying type in purescript

I'm trying to see if there's an easy way to get the type of a newtype'd record to put in function signatures.
newtype T1 = T1 { foo:: Int}
derive instance newtypeT1 :: Newtype T1 _
... other classes that require me to newtype the record ...
I know I can access a records members with
_.property and I can compose that with unwrap
unwrap >>> _.property to get a function for that property, but I'd like to write a function similar to
testFoo :: forall a. (_ -> a) -> Effect a
testFoo accessor = (unwrap >>> accessor) <$> loadT1
This works but the wildcard symbol gives an warning, but I'm not sure how to get that record definition from T1. (This is a minimal example, I have a massive property object that is from an external source.
A workaround I've been using for now has been to declare my type like
type InnerT1 = { foo ::Int}
newtype T1 = T1 InnerT1
and exporting that InnerT1 so it can be used in my test file, but this seems a bit clunky and I am wondering if there is a better way?
You can use the Newtype class to get at the inner type:
testFoo :: forall a inner. Newtype T1 inner => (inner -> a) -> Effect a
testFoo accessor = (unwrap >>> accessor) <$> loadT1
This works without additional annotations, because the class has a functional dependency Newtype a b | a -> b, which means that the inner type is uniquely determined by the outer type.

How to create Functor instance for Type composed of Either and Maybe

I'm having trouble with a Functor instance for a type which is basically just nested Either and Maybe.
data Tuple a b = Tuple a b
data Primitive = String String | Boolean Boolean | Number Number | Null
data JsonValue = Object (Map String JsonValue) | Array (List JsonValue) | Primitive
type Path = List String
data JsonGraphValue = JsonGraphObject (Map String JsonGraphValue) | Atom JsonValue | Ref Path | Error JsonValue | JsonPrimitive Primitive
newtype JsonGraphRecResult a = JsonGraphRecResult (Either String (Tuple (Maybe a) (List Path)))
instance jsonGraphRecResultFunctor :: Functor JsonGraphRecResult where
map f (JsonGraphRecResult (Right (Tuple (Just value) paths))) = JsonGraphRecResult (Right (Tuple (Just (f value)) paths))
map f value = value
I get the following error pointing to the "value" word at the end of the code above.
Could not match type
a1
with type
b0
while trying to match type JsonGraphRecResult a1
with type JsonGraphRecResult b0
while checking that expression value
has type JsonGraphRecResult b0
in value declaration jsonGraphRecResultFunctor
where b0 is a rigid type variable
a1 is a rigid type variable
It's not clear to me why JsonGraphRecResult is any different from the following Blah type which compiles fine:
newtype Blah a = Blah (Maybe a)
instance blahFunctor :: Functor Blah where
map f (Blah (Just x)) = Blah (Just (f x))
map f value = value
The following gist can be pasted directly into the "Try PureScript" online REPL in order to replicate the error.
Figured out the problem. I can't simply return the input value for the map function in the event that Either is Left, because the input value is not the right type. Here's a simplified version of the problem.
-- This is wrong because value is a Functor a, whereas map must return Functor b
map value#Nothing f = value
-- This is right, because even though both sides are Nothing, the right-hand side is a Maybe b vs. Maybe a
map Nothing f = Nothing
You should be able to just derive Functor instance for your type. But before you derive an instance for your final type you should derive it for your Tuple type (or just use Tuple from Data.Tuple ;-)):
data Tuple a b = Tuple a b
derive instance functorTuple :: Functor (Tuple a)
As you can see Functor instance can be defined only for types of kind * -> * so in this case we can map over type which occupies "last position" in Tuple.
In order to derive an instance for your JsonGraphRecResult you have to change order of types in it's internal Tuple to fulfill "last position" requirement:
newtype JsonGraphRecResult a =
JsonGraphRecResult (Either String (Tuple (List Path) (Maybe a)))
derive instance functorJsonGraphRecResult :: Functor JsonGraphRecResult
Here is relevant interactive snippet on trypurescript.org so you can play with this implementation.
There are more type classes for which you can use this deriving mechanism: Ord, Eq, Generic, Newtype...
It is also worth to point out in this context that in Purescript you have additional deriving option which is "newtype deriving". It's syntax is a bit different because it contains newtype keyword after derive - for example:
derive newtype instance someClassMyType :: SomeClass MyType
Newtype deriving is used for newtype "wrappers" for deriving instances of classes which given newtype internal type has already defined instances. In other words when you have newtype T = T a you can derive newtype instances for T for every class which a has instance of.
There is also another strategy - you can also use generic implementations of methods defined for some type classes in Data.Generic.Rep. These implementations can be used for types which are instances of Generic class... but this is whole another story ;-)
You can find more information about deriving in Phil's "24 Days of Purescript" series:
https://github.com/paf31/24-days-of-purescript-2016