infinite type inferred due to pattern variable - purescript

Using a pattern variable that names an entire case expression makes the difference between compiling correctly and the error "An infinite type was inferred for an expression". The following compiles correctly:
m = case Left "anything" of
e#(Left err) -> Left err
(Right f) -> case lookup "key" f of
Nothing -> Left "something else"
(Just x) -> Right x
However, if we use the pattern variable e (substituting e for "Left err", functionally equivalent), the compiler flags an error:
m = case Left "anything" of
e#(Left err) -> e
(Right f) -> case lookup "key" f of
Nothing -> Left "something else"
(Just x) -> Right x
"An infinite type was inferred for an expression: StrMap t1 while trying to match type t1 with type StrMap t1 while checking that expression case ((lookup "key") f) ...
I understand that matching StrMap t1 with t1 is problematic. I do not understand why this happens. Also, in my original code the message did not refer to infinite types at all. Here is the relevant extract:
retrieveDomeinResourceDefinition :: forall e.
ResourceId
-> Namespace
-> (AsyncDomeinFile e (Either String PropDefs))
retrieveDomeinResourceDefinition id ns = do
df <- retrieveDomeinFile (namespaceToDomeinFileName ns)
case df of
e#(Left err) -> pure $ e
(Right f) -> case lookup id f of
Nothing -> pure $ Left ("retrieveDomeinResourceDefinition: cannot find definition of " <> id <> " in DomeinFile for " <> ns)
(Just propDefs) -> pure (Right propDefs)
retrieveDomeinFile :: forall e. Namespace -> AsyncDomeinFile e (Either String DomeinFile)
newtype PropDefs = PropDefs (StrMap Json)
Now here the compiler tells me: "Could not match type: PropDefs with type StrMap PropDefs..." It appears as if the compiler does not notice the lookup expression. In fact, when I replace "pure (Right propDefs)" with "pure (Right f)", the error goes away (and another appears on the line binding df, which I understand).
Now I write this up I notice the similarity between 'trying to match type t1 with type StrMap t1' and 'could not match type: PropDefs with StrMap PropDefs'. Still, I don't see why using e introduces this problem.

Using the value from a pattern match that way may be functionally equivalent, but the types are not - the type system doesn't have the evidence that the type variable for the Right can be ignored.
Using the types in your second example - when you pattern match e#(Left err), the type of e will be Either String DomeinFile - but you want an Either String PropDefs. The pattern match does not "free up" the type variable on the right, which is why you have to reconstruct the Left with the error again.

Related

Understand Either as a Functor

Looking into how Either is defined as a functor, I can see that
derive instance functorEither :: Functor (Either a)
which reads to me as "You can map an Either so long as you can map its element.
But either doesn't have just one element. How would this be implemented without derive? Here's what I've tried:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ a = a
Of course, the types don't work here:
The Right has this signature: map :: forall a b. (a -> b) -> f a -> f b
The Left however, isn't okay: map :: forall a b. (a -> b) -> f a -> f a
Part of my intuition is saying that Either a b isn't a functor, only Either a is a functor. Which is why map works over Right and ignores Left
That doesn't really give me any intuition for how this is implemented. I still need a way of matching both constructors, don't I?
On the other hand, I think an implementation of map that replaces the inner function with identity is technically law-abiding for functor? The law of composition is met if you just ignore it?
While your proposed definition of the Functor instance indeed fails to compile, it isn't for the reason you say. And it's also "essentially" correct, just not written in a way that will satisfy the compiler.
For convenience, here's your definition again:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ a = a
and here's the actual error that you get when trying to compile it:
Could not match type
a02
with type
b1
while trying to match type Either a0 a02
with type Either a0 b1
while checking that expression a
has type Either a0 b1
in value declaration functorEither
where a0 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
b1 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
a02 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
I admit that's a little hard to interpret, if you're not expecting it. But it has to do with the fact that map for Either a needs to have type forall b c. (b -> c) -> Either a b -> Either a c. So the a on the left of map _ a = a has type Either a b, while the one on the right has type Either a c - these are different types (in general), since b and c can be anything, so you can't use the same variable, a, to denote a value of each type.
(This question, although about Haskell rather than Purescript, goes deeper into explanation of exactly this error.)
To fix it, as implied in the question above, you have to explicitly mention that the value you're mapping over is a Left value:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ (Left a) = Left a
which is fine because Left a can be interpreted on the left as of type Either a b and on the right as an Either a c.
As for what the instance "does": you are correct that "Either a b isn't a functor, only Either a is a functor" - because a functor must take one type variable, which Either a does but Either a b doesn't. And yes, because the type variable that actually "varies" between Either a b and Either a c is the one that is used in Right, map must only map over the Right values, and leave the Left ones alone - that's the only thing that will satisfy the types needed.
Either a b is often interpreted as representing the result of a computation, where Left values represent failure while Right ones represent success. In this sense it's a slightly "expanded" version of Maybe - the difference is that rather than failure being represented by a single value (Nothing), you get a piece of data (the a type in Either a b) which can tell you information about the error. But the Functor instance works identically to that for Maybe: it maps over any success, and leaves failures alone.
(But there's no logical reason why you can't "map over" the Left values as well. The Bifunctor class is an extension of Functor which can do exactly that.)

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 convert partial functions to safe(Maybe) functions?

I want it to use library-defined partialfunc more convenient, or write callback with partial pattern-matching.
like this,
partialMaybe :: forall a b. (Partial => a -> b) -> a -> Maybe b
I couldn't find similar in some major libraries.
How to define it? or already defined in libs?
data ABC a = A a | B a | C a
f1 = someHigherOrderFunc $ partialMaybe \(A a) -> someFunc a -- if not 'A', return Nothing.
-- same as
f2 = someHigherOrderFunc $ case _ of A a -> Just $ someFunc a
_ -> Nothing -- requires line break, seems syntax redundant...
using: purescript 0.11.6
Edit:
I did it...
partialMaybe :: forall a b. (Partial => a -> b) -> a -> Maybe b
partialMaybe f a = runPure $ catchException (const $ pure Nothing) (Just <<< unsafePartial f <$> pure a)
this is...umm...very ugly. it's not.
'Failed pattern match' exception is thrown by the purescript.
so I think it should be able to handle by purescript.
Can't do it?
If you want an exception if a case is missed, use Partial. If you want otherwise, use Maybe or Either or another appropriate sum type.
You can catch the exception thrown from a failed pattern match. There is no way for a failed pattern match to not throw an exception.

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).

Resolving Effects and Maybes

spec = describe "Router" $ do
let sampleRoutes = [( Tuple "/" "views/index.yaml" ),
( Tuple "/foo" "views/foo.yaml" ),
( Tuple "/bar" "views/bar.yaml" )]
it "should default to the first of the list" $ do
r <- fst <$> head sampleRoutes
fprint r
The above throws the following error:
Error in declaration spec
Cannot unify Data.Maybe.Maybe with Control.Monad.Eff.Eff u4505.
I believe its because it is expect a second argument that is of type Eff, but because of
the use of Maybe introduced by head the second arguments ends up being of type Maybe instead.
it :: forall e a. String -> Eff e a -> Eff (it :: It | e) Unit
The problem is, I have no idea how to resolve this. Can I not have a Maybe instead an effectful block of code?
Maybe can be used in a do block, but all of the actions in the block have to be of type Maybe a for some a.
The same is true for Eff eff - you can use Eff eff with do, but all actions have to be of type Eff eff a for some a.
You can't mix and match the two types of effects within a do block.
It looks like you want to use a value of type Maybe a inside a do block whose monad is Eff eff. You have a couple of options:
Use Data.Array.Unsafe.head which will give you an unwrapped Tuple, which you can call fst on directly.
Pattern match on the Maybe value to decide the course of action in the Eff monad:
it "should default to the first of the list" $ do
case head sampleRoutes of
Nothing -> ... -- Handle empty array
Just tuple -> fprint (fst tuple) -- Print the first component
.. rest of do block ..
In this example, it's also possible to make use of traverse_ from Data.Foldable.
Since you're working with a Maybe (Tuple String String), Maybe has a Foldable instance, and Eff e has an applicative instance, you can use traverse_ rather than (<$>).
You just need to supply a function Tuple String String -> Eff e a for some a. If you compose fst and fprint, you get exactly that.
Your example becomes
spec = describe "Router" $ do
let sampleRoutes = [( Tuple "/" "views/index.yaml" ),
( Tuple "/foo" "views/foo.yaml" ),
( Tuple "/bar" "views/bar.yaml" )]
it "should default to the first of the list" $
traverse_ (fst >>> fprint) $ head sampleRoutes