Understanding Purescript Type Mismatch Compilor Error - purescript

The Problem:
I can't find my way to understand the error in this code:
import Prelude
import Data.Array.ST (STArray, modify, run, thaw, freeze)
mpi :: forall a. Array a -> Array a
mpi array = run do
mutableArray <- thaw array
freeze mutableArray
The error:
Could not match type
Array
with type
STArray h0
while trying to match type Array a2
with type STArray h0 t1
while checking that expression (bind (thaw array)) (\mutableArray ->
freeze mutableArray
)
has type ST h0 (STArray h0 t1)
in value declaration mpi
where a2 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
h0 is a rigid type variable
bound at (line 9, column 17 - line 11, column 22)
t1 is an unknown type
It says t1 is an unknown type, but I'm pretty sure it should be a2. I'm not sure how or where t1 is introduced. thaw should return type ST h (STArray h a) which gets bound to mutableArray :: STArray h a
If I specialize this function, it becomes clearer but no less confusing
mpi :: Array Int -> Array Int
mpi array = run do
mutableArray <- thaw array
freeze mutableArray
I get this error:
Could not match type
Array
with type
STArray h0
while trying to match type Array Int
with type STArray h0 t1
while checking that expression (bind (thaw array)) (\mutableArray ->
freeze mutableArray
)
has type ST h0 (STArray h0 t1)
in value declaration mpi
where h0 is a rigid type variable
bound at (line 9, column 17 - line 11, column 22)
t1 is an unknown type
If I explicitly type the left-hand side,
mpi :: Array Int -> Array Int
mpi array = run do
(mutableArray :: STArray _ Int) <- thaw array
freeze mutableArray
or write it without do notation:
mpi :: Array Int -> Array Int
mpi array = run $ thaw array >>= freeze
The error doesn't really change. In each case, I have trouble understanding where t1 is introduced.
The Question:
What's wrong with what I've written?
What steps could I be taking with similar problems in the future to debug this on my own?

You're using the wrong version of run.
The one you're using is from Data.Array.ST.
But the one your code assumes is from Control.Monad.ST.
The former takes an ST computation that returns an STArray, and then runs that computation, freezes the resulting array, and returns it as an immutable array.
The latter takes an ST computation that returns something, and then runs that computation and returns the resulting something.
Your do block is returning Array a, but then you're calling Data.Array.ST.run, which expects STArray h a, so the types don't match. This is exactly what the error message says: can't match Array a with STArray h a.
Fix option 1: import the other run:
import Prelude
import Control.Monad.ST (run)
import Data.Array.ST (STArray, modify, thaw, freeze)
mpi :: forall a. Array a -> Array a
mpi array = run do
mutableArray <- thaw array
freeze mutableArray
Fix option 2: return the STArray from your do block, don't freeze it:
import Prelude
import Data.Array.ST (STArray, modify, run, thaw, freeze)
mpi :: forall a. Array a -> Array a
mpi array = run do
mutableArray <- thaw array
pure mutableArray

Related

convert Array with DIM2 to list in repa

I have loaded a two dimensional array into a Rep Array with fromList and can apply a Fourier transformation to it (fftd2), but I have difficulties to convert the result back to a list. I clearly do not understand much about Repa but was successful to run one dimensional examples. With 2 dimension I fail:
With
g88:: Array F DIM2 (Complex Double)
g88 = fromList (Z :. 8 :. 11) grid88
g88f :: Array F DIM2 (Complex Double)
g88f = fft2d g88
g88list :: [Complex Double]
g88list = toList g88f
I get the runtime error:
** Exception: Data.Array.Repa.Eval.Fill.fromList: provide array shape does not match list length
CallStack (from HasCallStack):
error, called at ./Data/Array/Repa/Eval/Target.hs:43:15 in repa-3.4.1.5
What is the meaning of the error message? The type of
toList :: (Shape sh, Source r e) => Array r sh e -> [e]
does not indicate any other parameter and the input seems to have an appropriate type.
How to get the data back to a list?

How declare tagged union of polymorphic collection types

I'm new to Purescript. My current learning exercise is to create a tagged union of polymorphic Array and List. I'll use it in a function that finds the length of any Array or List. Here's my attempt:
import Data.List as L
import Data.Array as A
data Collection = CollectionList (forall a. L.List a)
| CollectionArray (forall b. Array b)
colLength :: Collection -> Int
colLength (CollectionList list) = L.length list
colLength (CollectionArray arr) = A.length arr
main :: Effect Unit
main = do
logShow (colLength (CollectionArray [3,5]))
The compiler doesn't like it:
Could not match type Int with type b0
while checking that type Int is at least as general as type b0
while checking that expression 3 has type b0
in value declaration main
where b0 is a rigid type variable
I'm confused by the parts, checking that type Int is at least as general as type b0 and b0 is a rigid type variable. My intention was to allow b to be anything. Not sure what I did to make the compiler put conditions on what b can be.
If you know how, please show the correct way to define a tagged union of polymoric types that'll work in my colLength function.
forall a doesn't mean "any type goes here"
It means that whoever accesses the value, gets to choose what a is, and whoever provides the value has to make sure that the value is of that type. It's a contract between the provider and the consumer.
So when you provide the value CollectionArray [3,5], you have to make it such that it works for all possible a that whoever accesses that value later might choose.
Obviously, there is only one way you can construct such value:
CollectionArray []
What you probably actually meant to do (and I'm guessing here) was to make your collection polymorphic, in the sense that it can contain values of any type, but the type is chosen by whoever creates the collection, and then whoever accesses it later has to deal with that particular type.
To do that, you have to put the type variable on the outside:
data Collection a = CollectionList (L.List a)
| CollectionArray (Array a)
That way, when you create a collection CollectionArray [3,5], it becomes of type Collection Int, and now everywhere you pass it, such as colLength, will have to deal with that Int
This, in turn, can be achieved by making colLength itself generic:
colLength :: forall a. Collection a -> Int
colLength (CollectionList list) = L.length list
colLength (CollectionArray arr) = A.length arr
Now whoever accesses (i.e. calls) colLength itself gets to choose what a is, which works fine, because it's the same place that created the Connection Int in the first place.

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

How to use instance chain to solve overlapping

I've been trying next purescript ver 0.12.0-rc1.
I have a question how to use new feature 'instance chain'.
in my understanding the instance chain provides a feature to be able to specify instance resolving order explicitly. this solves avoid instance definition overlapping.
so I suppose it may work:
class A a
class B b
class C c where
c :: c -> String
instance ca :: A a => C a where
c = const "ca"
else
instance cb :: B b => C b where
c = const "cb"
data X = X
instance bx :: B X
main :: forall eff. Eff (console :: CONSOLE | eff) Unit
main = logShow $ c X
but cannot compiled.
what is not correctly?
or what is the instance chain usage?
result:
Error found:
in module Main
at src/Main.purs line 23, column 8 - line 23, column 20
No type class instance was found for
Main.A X
while applying a function c
of type C t0 => t0 -> String
to argument X
while inferring the type of c X
in value declaration main
where t0 is an unknown type
Even with instance chains matching is still done on the head of an instance. There is no "backtracking" when any of constraint fails for the chosen instance.
Your instances are completely overlapping on the head, so your first instance always matches before second one and it fails because there is no A instance for X.
Instance chains allows you to define explicit ordering of instance resolution without relying on for example alphabetical ordering of names etc. (as it was done till 0.12.0 version - please check the third paragraph here). For example you can define this overlapping scenario:
class IsRecord a where
isRecord :: a -> Boolean
instance a_isRecordRecord :: IsRecord (Record a) where
isRecord _ = true
instance b_isRecordOther :: IsRecord a where
isRecord _ = false
as
instance isRecordRecord :: IsRecord (Record a) where
isRecord _ = true
else instance isRecordOther :: IsRecord a where
isRecord _ = false
I hope it compiles - I don't have purs-0.12.0-rc yet ;-)

Pattern matching on the result of type computing functions in idris

Consider the following fragment:
import Data.List
%default total
x : Elem 1 [1, 2]
x = Here
type : Type
type = Elem 1 [1, 2]
y : type
y = Here
This gives the error:
When checking right hand side of y:
Type mismatch between
Elem x (x :: xs) (Type of Here)
and
iType (Expected type)
The type of y, when queried, is:
type : Type
-----------
y : type
Is it possible to force type to be evaluated during or before the type ascription of y, so that the type of y is Elem 1 [1, 2]?
My use case is that I want to be able to define generic predicates that return the right proposition terms for proofs, for example:
subset : List a -> List a -> Type
subset xs ys = (e : a) -> Elem e xs -> Elem e ys
thm_filter_subset : subset (filter p xs) xs
Names in type declarations which begin with a lower case letter are implicitly bound, so it's treating 'type' as a type parameter. You can either give 'type' a new name which begins with a capital (by convention this is what most people do in Idris) or you can explicitly qualify the name with the module it's in (Main, here).
Idris used to try guessing whether names such as 'type' were intended as an implicit or intended to refer to the global, as here. There's all kinds of voodoo involved in getting this right though, so it often failed, and so it now implements this much simpler rule. It's slightly annoying in cases such as this, but the alternative behaviour was more often annoying (and harder to explain).