Повторить параметр типа экзистенциального экземпляра

У меня есть такой код:

{-# LANGUAGE AllowAmbiguousTypes #-}
module Foo where

import Data.Proxy

class Foo x y
class Bar x y
class Baz x y
  where
  baz :: Proxy x -> Proxy y -> ()

instance (Foo a v, Bar b v) => Baz a b
  where
  baz _ _ = ()

instance Foo String String
instance Bar Int String

Теперь я действительно хочу использовать этот экземпляр Baz, поэтому я пишу:

test :: Proxy String -> Proxy Int -> ()
test = baz

Но, конечно, есть неоднозначный экзистенциальный параметр типа v, который я еще не зафиксировал на String (и нет фундэпса), так что я получаю:

[typecheck] [E] /tmp/foo/src/Main.hs:20:8: error:
    • Ambiguous type variable ‘v1’ arising from a use of ‘baz’
      prevents the constraint ‘(Foo [Char] v1)’ from being solved.
      Probable fix: use a type annotation to specify what ‘k1’,
                                                          ‘v1’ should be.
      These potential instance exist:
        one instance involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: baz
      In an equation for ‘test’: test = baz

Но как я могу исправить эту переменную типа? Я не вижу способа исправить это с помощью приложения видимого типа, потому что, например, следующее не работает:

test2 :: Proxy String -> Proxy Int -> ()
test2 = baz @String @Int @String -- is there some variation of this that would work?

Я также не вижу способа использовать явную аннотацию типа для исправления этого параметра типа. Я написал экземпляр, который невозможно использовать на самом деле?


person Asad Saeeduddin    schedule 06.07.2020    source источник


Ответы (1)


Использовать этот экземпляр действительно невозможно. Когда вы вызываете baz, вы можете указать a и b, но не v. v должен был бы определяться некоторой комбинацией ограничений суперкласса и экземпляра, а это не так.

Вы должны быть в состоянии исправить это в разных местах. Попробуйте либо

instance s ~ String => Foo String s

or

instance s ~ String => Bar Int s

Например.

person dfeuer    schedule 06.07.2020
comment
Спасибо за объяснение. Я попытался заменить instance Foo String String на instance s ~ String => Foo String s, но это, похоже, не имело никакого значения в том, что касается сообщения об ошибке. Я неправильно понимаю предложение в ответе? - person Asad Saeeduddin; 13.07.2020
comment
@AsadSaeeduddin, нет, я что-то пропустил. Вы пробовали мой другой вариант? - person dfeuer; 13.07.2020