How do I get the name of the constructor for a product type in purescript?? Similar to haskell conNameOf - purescript

I want to extract the value of the constructor for my data which is a sum of product types data X = Xa A | Xb B | Xcd C D | Xefg E F G.... , where A B C... are of the type data A = A {a :: xyz , b :: abc..}
I want a function that gets takes in a value of type X and gives me "Xa", "Xb" .. based on the type. I know I can use case but is there a better way to do this?? Haskell has the toConstr function for this purpose,

I don't think there is a function in the standard library, but if you don't mind using the RTTI mechanisms (which is what conNameOf is using), you can relatively easily make your own using Generic: just convert the value to its generic representation using from, and then extract the constructor by matching on Sum and Constructor:
class ConstrName rep where
constrName' :: rep -> String
instance IsSymbol name => ConstrName (Constructor name a) where
constrName' (Constructor _) = reflectSymbol (Proxy :: Proxy name)
instance (ConstrName a, ConstrName b) => ConstrName (Sum a b) where
constrName' (Inl a) = constrName' a
constrName' (Inr b) = constrName' b
constrName :: forall a rep. Generic a rep => ConstrName rep => a -> String
constrName a = constrName' $ from a
Usage:
> constrName (Xa $ A { a: ..., b: ..., .... })
"Xa"

Related

Mapping homogeneous record type

Suppose we have a record type that is homogeneous.
type RecI = { a :: Int, b :: Int, c :: Int, d :: Int, e :: Int }
We want to get from it type with the same keys but different value type:
type RecS = { a :: String, b :: String, c :: String, d :: String, e :: String }
Is it possible to get RecS type without explicitly defining all the keys from RecI?
And the second part of the question, what is the best way to implement mapping function from one type to another:
mapItoS :: (Int -> String) -> RecI -> RecS
?
To get a free-ish conversion from Int to String at type level, just give your record a parameter, then instantiate it with Int to get RecI and with String to get RecS:
type Rec a = { a :: a, b :: a, c :: a, d :: a, e :: a }
type RecI = Rec Int
type RecS = Rec String
To implement mapItoS, you can first convert to a Foreign.Object using fromHomogeneous, then map the function over it, then convert back to the record.
Unfortunately there is no toHomogeneous function, because in general you can't be sure that the Foreign.Object actually contains all required keys. But no matter: in this particular case you can be sure that it does, so you can get away with unsafeCoerce:
mapItoS :: forall a b. (a -> b) -> Rec a -> Rec b
mapItoS f = fromHomogeneous >>> map f >>> unsafeCoerce
A small self plug which is strictly relevant to the question :-P I've just published a library which provides many instances which allow a PureScripter to work with homogeneous Record and Variant:
https://pursuit.purescript.org/packages/purescript-homogeneous
I think it should have much better inference than solutions like heterogeneous. Please check it out and let me know what do you think.

Similar record types in a list/array in purescript

Is there any way to do something like
first = {x:0}
second = {x:1,y:1}
both = [first, second]
such that both is inferred as {x::Int | r} or something like that?
I've tried a few things:
[{x:3}] :: Array(forall r. {x::Int|r}) -- nope
test = Nil :: List(forall r. {x::Int|r})
{x:1} : test -- nope
type X r = {x::Int | r}
test = Nil :: List(X) -- nope
test = Nil :: List(X())
{x:1} : test
{x:1, y:1} : test -- nope
Everything I can think of seems to tell me that combining records like this into a collection is not supported. Kind of like, a function can be polymorphic but a list cannot. Is that the correct interpretation? It reminds me a bit of the F# "value restriction" problem, though I thought that was just because of CLR restrictions whereas JS should not have that issue. But maybe it's unrelated.
Is there any way to declare the list/array to support this?
What you're looking for is "existential types", and PureScript just doesn't support those at the syntax level the way Haskell does. But you can roll your own :-)
One way to go is "data abstraction" - i.e. encode the data in terms of operations you'll want to perform on it. For example, let's say you'll want to get the value of x out of them at some point. In that case, make an array of these:
type RecordRep = Unit -> Int
toRecordRep :: forall r. { x :: Int | r } -> RecordRep
toRecordRep {x} _ = x
-- Construct the array using `toRecordRep`
test :: Array RecordRep
test = [ toRecordRep {x:1}, toRecordRep {x:1, y:1} ]
-- Later use the operation
allTheXs :: Array Int
allTheXs = test <#> \r -> r unit
If you have multiple such operations, you can always make a record of them:
type RecordRep =
{ getX :: Unit -> Int
, show :: Unit -> String
, toJavaScript :: Unit -> Foreign.Object
}
toRecordRep r =
{ getX: const r.x
, show: const $ show r.x
, toJavaScript: const $ unsafeCoerce r
}
(note the Unit arguments in every function - they're there for the laziness, assuming each operation could be expensive)
But if you really need the type machinery, you can do what I call "poor man's existential type". If you look closely, existential types are nothing more than "deferred" type checks - deferred to the point where you'll need to see the type. And what's a mechanism to defer something in an ML language? That's right - a function! :-)
newtype RecordRep = RecordRep (forall a. (forall r. {x::Int|r} -> a) -> a)
toRecordRep :: forall r. {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
allTheXs = test <#> \(RecordRep r) -> r _.x
The way this works is that RecordRep wraps a function, which takes another function, which is polymorphic in r - that is, if you're looking at a RecordRep, you must be prepared to give it a function that can work with any r. toRecordRep wraps the record in such a way that its precise type is not visible on the outside, but it will be used to instantiate the generic function, which you will eventually provide. In my example such function is _.x.
Note, however, that herein lies the problem: the row r is literally not known when you get to work with an element of the array, so you can't do anything with it. Like, at all. All you can do is get the x field, because its existence is hardcoded in the signatures, but besides the x - you just don't know. And that's by design: if you want to put anything into the array, you must be prepared to get anything out of it.
Now, if you do want to do something with the values after all, you'll have to explain that by constraining r, for example:
newtype RecordRep = RecordRep (forall a. (forall r. Show {x::Int|r} => {x::Int|r} -> a) -> a)
toRecordRep :: forall r. Show {x::Int|r} => {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r
test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]
showAll = test <#> \(RecordRep r) -> r show
Passing the show function like this works, because we have constrained the row r in such a way that Show {x::Int|r} must exist, and therefore, applying show to {x::Int|r} must work. Repeat for your own type classes as needed.
And here's the interesting part: since type classes are implemented as dictionaries of functions, the two options described above are actually equivalent - in both cases you end up passing around a dictionary of functions, only in the first case it's explicit, but in the second case the compiler does it for you.
Incidentally, this is how Haskell language support for this works as well.
Folloing #FyodorSoikin answer based on "existential types" and what we can find in purescript-exists we can provide yet another solution.
Finally we will be able to build an Array of records which will be "isomorphic" to:
exists tail. Array { x :: Int | tail }
Let's start with type constructor which can be used to existentially quantify over a row type (type of kind #Type). We are not able to use Exists from purescript-exists here because PureScript has no kind polymorphism and original Exists is parameterized over Type.
newtype Exists f = Exists (forall a. f (a :: #Type))
We can follow and reimplement (<Ctrl-c><Ctrl-v> ;-)) definitions from Data.Exists and build a set of tools to work with such Exists values:
module Main where
import Prelude
import Unsafe.Coerce (unsafeCoerce)
import Data.Newtype (class Newtype, unwrap)
newtype Exists f = Exists (forall a. f (a :: #Type))
mkExists :: forall f a. f a -> Exists f
mkExists r = Exists (unsafeCoerce r :: forall a. f a)
runExists :: forall b f. (forall a. f a -> b) -> Exists f -> b
runExists g (Exists f) = g f
Using them we get the ability to build an Array of Records with "any" tail but we have to wrap any such a record type in a newtype before:
newtype R t = R { x :: Int | t }
derive instance newtypeRec :: Newtype (R t) _
Now we can build an Array using mkExists:
arr :: Array (Exists R)
arr = [ mkExists (R { x: 8, y : "test"}), mkExists (R { x: 9, z: 10}) ]
and process values using runExists:
x :: Array [ Int ]
x = map (runExists (unwrap >>> _.x)) arr

Purescript: Could not match type

In the REPL this works:
> mm n = (\n -> n * 2) <$> n
> mm (2:3:Nil)
(4 : 6 : Nil)
in a file this compiles and I can run it:
squareOf ls =
map (\n -> n * n) ls
however when I add a type definition to that function
squareOf :: List Int -> Int
squareOf ls =
map (\n -> n * n) ls
I get an error:
Could not match type
List Int
with type
Int
while checking that type t0 t1
is at least as general as type Int
while checking that expression (map (\n ->
(...) n
)
)
ls
has type Int
in value declaration squareOf
where t0 is an unknown type
t1 is an unknown type
I tried changing the signature to a type alias of the list, and also I tried a forall definition with no luck.
If I inspect the definition created when I don't put signatures in my function I get:
forall t2 t3. Functor t2 => Semiring t3 => t2 t3 -> t2 t3
Can anyone explain why my signature is incorrect and also why am I getting this signature for the function?
Cheers
Edit: Thanks for the comments, updating the fn definition so it returns a List Int as well, and , of course it solves the problem
Assuming you're repl function is the behaviour you're after, you've missed out the map operator (<$>) in your later definitions.
Your repl function (with variables renamed for clarity) has the type:
mm :: forall f. Functor f => f Int -> f Int
mm ns = (\n -> n * 2) <$> ns
Which is to say: mm maps "times two" to something that is mappable" (i.e. a Functor)
Aside: you could be more concise/clear in your definition here:
mm :: forall f. Functor f => f Int -> f Int
mm = map (_*2)
This is similar to your squareOf definition, only now you're squaring so your use of (*) is more general:
squareOf :: forall f. Functor f => Semiring n => f n -> f n
squareOf = map \n -> n * n
Because (*) is a member of the Semiring typeclass.
But the signature you gave it suggests you're after some kind of fold? Let me know what output you expect from your squareOf function and I'll update the answer accordingly.
Here is map:
class Functor f where
map :: forall a b. (a -> b) -> f a -> f b
Narrowing to List Int and Int -> Int, the compiler infers
map :: (Int -> Int) -> List Int -> List Int
So, in squareOf, the expression reduces to a list of integers, not an integer. That is why the compiler complains.

Higher kinded Types and Type arguments for classes

Suppose you are using the FlexibleInstances extension and have the class
class C a where
f :: a b -> Maybe b
how would you implement it for a list of lists of a datatype. In particular, how would the type be written. The only thing I could find is how to do it for a single list, but not a list of lists or lists of any other datatypes.
This works:
instance C [] where
...
But this doesn't
data D = ...
instance C [[D]] where
...
How can I express something like this?
You need a newtype
class C a where
f :: a b -> b -- the class before the OP edited
newtype LL a = LL [[a]]
instance C LL where
f (LL xss) = ...
However, it is impossible to write a completely meaningful instance, since if the lists-of-lists is empty, it is impossible to extract an element. the best we could do is
instance C LL where
f (LL xss) = case concat xss of
(x:_) -> x
_ -> error "f: no elements"
I'm not sure if that is a good idea.
As an alternative, you could use type families or functional dependencies. Here's a solution with type families.
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
class C a where
type T a
f :: a -> Maybe (T a)
instance C [[b]] where
type T [[b]] = b
f xss = case concat xss of
[] -> Nothing
(x:_) -> Just x

Defining multiple-type container classes in haskell, trouble binding variables

I'm having trouble with classes in haskell.
Basically, I have an algorithm (a weird sort of graph-traversal algorithm) that takes as input, among other things, a container to store the already-seen nodes (I'm keen on avoiding monads, so let's move on. :)). The thing is, the function takes the container as a parameter, and calls just one function: "set_contains", which asks if the container... contains node v. (If you're curious, another function passed in as a parameter does the actual node-adding).
Basically, I want to try a variety of data structures as parameters. Yet, as there is no overloading, I cannot have more than one data structure work with the all-important contains function!
So, I wanted to make a "Set" class (I shouldn't roll my own, I know). I already have a pretty nifty Red-Black tree set up, thanks to Chris Okasaki's book, and now all that's left is simply making the Set class and declaring RBT, among others, as instances of it.
Here is the following code:
(Note: code heavily updated -- e.g., contains now does not call a helper function, but is the class function itself!)
data Color = Red | Black
data (Ord a) => RBT a = Leaf | Tree Color (RBT a) a (RBT a)
instance Show Color where
show Red = "r"
show Black = "b"
class Set t where
contains :: (Ord a) => t-> a-> Bool
-- I know this is nonesense, just showing it can compile.
instance (Ord a) => Eq (RBT a) where
Leaf == Leaf = True
(Tree _ _ x _) == (Tree _ _ y _) = x == y
instance (Ord a) => Set (RBT a) where
contains Leaf b = False
contains t#(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
Note how I have a pretty stupidly-defined Eq instance of RBT. That is intentional --- I copied it (but cut corners) from the gentle tutorial.
Basically, my question boils down to this: If I comment out the instantiation statement for Set (RBT a), everything compiles. If I add it back in, I get the following error:
RBTree.hs:21:15:
Couldn't match expected type `a' against inferred type `a1'
`a' is a rigid type variable bound by
the type signature for `contains' at RBTree.hs:11:21
`a1' is a rigid type variable bound by
the instance declaration at RBTree.hs:18:14
In the second argument of `(==)', namely `x'
In a pattern guard for
the definition of `contains':
b == x
In the definition of `contains':
contains (t#(Tree c l x r)) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
And I simply cannot, for the life of me, figure out why that isn't working. (As a side note, the "contains" function is defined elsewhere, and basically has the actual set_contains logic for the RBT data type.)
Thanks! - Agor
Third edit: removed the previous edits, consolidated above.
You could also use higher-kinded polyphormism. The way your class is defined it sort of expects a type t which has kind *. What you probably want is that your Set class takes a container type, like your RBT which has kind * -> *.
You can easily modify your class to give your type t a kind * -> * by applying t to a type variable, like this:
class Set t where
contains :: (Ord a) => t a -> a -> Bool
and then modify your instance declaration to remove the type variable a:
instance Set RBT where
contains Leaf b = False
contains t#(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
So, here is the full modified code with a small example at the end:
data Color = Red | Black
data (Ord a) => RBT a = Leaf | Tree Color (RBT a) a (RBT a)
instance Show Color where
show Red = "r"
show Black = "b"
class Set t where
contains :: (Ord a) => t a -> a -> Bool
-- I know this is nonesense, just showing it can compile.
instance (Ord a) => Eq (RBT a) where
Leaf == Leaf = True
(Tree _ _ x _) == (Tree _ _ y _) = x == y
instance Set RBT where
contains Leaf b = False
contains t#(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
tree = Tree Black (Tree Red Leaf 3 Leaf) 5 (Tree Red Leaf 8 (Tree Black Leaf 12 Leaf))
main =
putStrLn ("tree contains 3: " ++ test1) >>
putStrLn ("tree contains 12: " ++ test2) >>
putStrLn ("tree contains 7: " ++ test3)
where test1 = f 3
test2 = f 12
test3 = f 7
f = show . contains tree
If you compile this, the output is
tree contains 3: True
tree contains 12: True
tree contains 7: False
You need a multi-parameter type class. Your current definition of Set t doesn't mention the contained type in the class definition, so the member contains has to work for any a. Try this:
class Set t a | t -> a where
contains :: (Ord a) => t-> a-> Bool
instance (Ord a) => Set (RBT a) a where
contains Leaf b = False
contains t#(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
The | t -> a bit of the definition is a functional dependency, saying that for any given t there is only one possible a. It's useful to have (when it makes sense) since it helps the compiler figure out types and reduces the number of ambiguous type problems you often otherwise get with multi-parameter type classes.
You'll also need to enable the language extensions MultiParamTypeClasses and FunctionalDependencies at the top of your source file:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
The error means that the types don't match. What is the type of contains? (If its type is not something like t -> a -> Bool as set_contains is, something is wrong.)
Why do you think you shouldn't roll your own classes?
When you write the instance for Set (RBT a), you define contains for the specific type a only. I.e. RBT Int is a set of Ints, RBT Bool is a set of Bools, etc.
But your definition of Set t requires that t be a set of all ordered a's at the same time!
That is, this should typecheck, given the type of contains:
tree :: RBT Bool
tree = ...
foo = contains tree 1
and it obviously won't.
There are three solutions:
Make t a type constructor variable:
class Set t where
contains :: (Ord a) => t a -> a-> Bool
instance Set RBT where
...
This will work for RBT, but not for many other cases (for example, you may want to use a bitset as a set of Ints.
Functional dependency:
class (Ord a) => Set t a | t -> a where
contains :: t -> a -> Bool
instance (Ord a) => Set (RBT a) a where
...
See GHC User's Guide for details.
Associated types:
class Set t where
type Element t :: *
contains :: t -> Element t -> Bool
instance (Ord a) => Set (RBT a) where
type Element (RBT a) = a
...
See GHC User's Guide for details.
To expand on Ganesh's answer, you can use Type Families instead of Functional Dependencies. Imho they are nicer. And they also change your code less.
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
class Set t where
type Elem t
contains :: (Ord (Elem t)) => t -> Elem t -> Bool
instance (Ord a) => Set (RBT a) where
type Elem (RBT a) = a
contains Leaf b = False
contains (Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b