Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error involving uverb #1381

Open
fisx opened this issue Dec 8, 2020 · 9 comments
Open

error involving uverb #1381

fisx opened this issue Dec 8, 2020 · 9 comments
Assignees
Labels
uverb Bugs and questions related to UVerb

Comments

@fisx
Copy link
Member

fisx commented Dec 8, 2020

If you copy the following code into Servant.API.UVerb.Union:

data User tag = User

type XS tag = Union '[User tag, ()]

f :: forall tag m. Applicative m => User tag -> m (XS tag)
f usr = either respond respond $ (undefined :: Either () (User tag))

respond ::
  forall (x :: *) (xs :: [*]) (f :: * -> *).
  (Applicative f, IsMember x xs) =>
  x ->
  f (Union xs)
respond = pure . inject . I

you get:

Servant/API/UVerb/Union.hs:159:24: warning: [-Wdeferred-type-errors]
    • Expected one of:
          '[User tag, ()]
      But got:
          User tag
    • In the second argument of ‘either’, namely ‘respond’
      In the expression: either respond respond
      In the expression:
        either respond respond $ (undefined :: Either () (User tag))
    |
159 | f usr = either respond respond $ (undefined :: Either () (User tag))
    |                        ^^^^^^^

Without the phantom tag, it compiles fine. I would have expected it to compile both ways.

@fisx
Copy link
Member Author

fisx commented Dec 8, 2020

Now I also get this:

Servant/API/UVerb/Union.hs:154:24: warning: [-Wdeferred-type-errors]
    • Overlapping instances for UElem (User tag0) '[User tag, ()]
        arising from a use of ‘respond’
      Matching instances:
        instance [overlapping] forall a (x :: a) (xs :: [a]) (x' :: a).
                               UElem x xs =>
                               UElem x (x' : xs)
          -- Defined at Servant/API/UVerb/Union.hs:109:30
        instance [overlapping] forall a (x :: a) (xs :: [a]).
                               UElem x (x : xs)
          -- Defined at Servant/API/UVerb/Union.hs:104:30
      (The choice depends on the instantiation of ‘k0, tag0, k, tag’
       To pick the first instance above, use IncoherentInstances
       when compiling the other instance declarations)
    • In the second argument of ‘either’, namely ‘respond’
      In the expression: either respond respond
      In the expression:
        either respond respond $ (undefined :: Either () (User tag))
    |
154 | f usr = either respond respond $ (undefined :: Either () (User tag))
    |                        ^^^^^^^

Even if i turn on incoherent instances.

@arianvp
Copy link
Member

arianvp commented Dec 14, 2020

My feeling is that our type-error type-family is hiding the true error in your first example. Could you try commenting out our friendly error messages and see if the error is more helpful?

@mheinzel
Copy link
Contributor

I think the type equality operator (==) chokes on the type variable.

ghci> type family CheckEqual a b :: Constraint where { CheckEqual a b = If (a == b) (() :: Constraint) (a ~ b) }
ghci> test :: CheckEqual a b => a -> b -> IO () ; test _ _ = putStrLn "equal types!"
ghci> test [True] [False]
equal types!
ghci> test [] []

<interactive>:43:1: error:
    • Could not deduce: If (a0 == a1) (() :: Constraint) ([a0] ~ [a1])
        arising from a use of ‘test’
    • In the expression: test [] []
      In an equation for ‘it’: it = test [] []

@arianvp
Copy link
Member

arianvp commented Dec 14, 2020

That makes sense. [] :: forall a. [a] and [] :: forall b. [b] are different types and aren't equal. You run into extensionality problems here

@mheinzel
Copy link
Contributor

mheinzel commented Dec 14, 2020

Ah, yeah, not the best example. But it can be adapted to be closer to the original issue (having the same type variable on both sides), still showing the same problem:

Prelude Data.Type.Equality Data.Type.Bool Data.Kind> test :: CheckEqual a a => a  -> IO () ; test _ _ = putStrLn "equal!"
Prelude Data.Type.Equality Data.Type.Bool Data.Kind> test []

<interactive>:45:1: error:
    • Could not deduce: If (a0 == a0) (() :: Constraint) ([a0] ~ [a0])
        arising from a use of ‘test’
    • In the expression: test []
      In an equation for ‘it’: it = test []

So == works differently to ~, it doesn't try to unify variables and it doesn't consider a variable to be equal to itself.

@arianvp
Copy link
Member

arianvp commented Dec 14, 2020

Yeh checking equality on polymorphic types does not work in Haskell.

Hence you can only call respond on monomorphic types or you need to delay the equality check up. e.g.:

f :: forall tag m. (Elem (User tag) [User tag, ()] , Applicative m) => User tag -> m (Union '[User tag, ()])
f usr = either respond respond $ (undefined :: Either () (User tag))

@arianvp
Copy link
Member

arianvp commented Dec 14, 2020

Yeh (==) is a type-level function; not some special unification thing:

https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.Type.Equality.html#%3D%3D

@mheinzel
Copy link
Contributor

Yes, propagating the constraint up is a decent workaround.

@fisx
Copy link
Member Author

fisx commented Dec 14, 2020

Cool, thanks for solving this! We should add this to the cookbook before closing the issue. I'll assign it to myself!

@fisx fisx self-assigned this Dec 14, 2020
@tchoutri tchoutri added the uverb Bugs and questions related to UVerb label Jun 11, 2022
guibou added a commit to guibou/servant that referenced this issue Dec 22, 2022
The `Elem` call was not possible to resolve with polymophic type. For
example, the following `forall a. Elem (Maybe a) '[Maybe a, Int]` cannot
be resolved.

I don't really understand the reasons why, looks like the former
implementation with `If (a == b)` does not work with polymophic types.

The new implementation uses pattern matching in closed type families.

Close haskell-servant#1590 and haskell-servant#1381.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
uverb Bugs and questions related to UVerb
Projects
None yet
Development

No branches or pull requests

4 participants