Здесь я определил два класса: F
и O
. F
предназначен для полиморфной функции f
и O
для полиморфного значения o
.Почему это выражение неоднозначно?
{-# LANGUAGE MultiParamTypeClasses #-}
class F a b where
f :: a -> b
class O a where
o :: a
data K = K
data L = L
data M = M
instance O K where
o = K
instance O L where
o = L
instance F K L where
f K = L
instance F L K where
f L = K
instance F L L where
f L = L
instance F M K where
f M = K
Чтобы сделать это легко, вот список возможных случаев для любого класса:
F K L
F L K
F L L
F M K
O K
O L
Теперь, если я ввожу следующее в GHCi:
f o :: K
Я ожидаю, что Haskell что конечный результат должен быть K
, это означает, что возможные случаи для f
: F M K
и F L K
, но с o
может быть только L
, но не M
, это должно быть так, что o
является L
и f
является F L K
. То есть без какой-либо другой возможности результат должен быть K
. Однако, оказывается, Haskell не может понять это:
*Main> f o :: K
<interactive>:2:1:
No instance for (F a0 K) arising from a use of `f'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance F M K -- Defined at hw.hs:28:10
instance F L K -- Defined at hw.hs:22:10
Possible fix: add an instance declaration for (F a0 K)
In the expression: f o :: K
In an equation for `it': it = f o :: K
<interactive>:2:3:
No instance for (O a0) arising from a use of `o'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance O L -- Defined at hw.hs:16:10
instance O K -- Defined at hw.hs:13:10
In the first argument of `f', namely `o'
In the expression: f o :: K
In an equation for `it': it = f o :: K
Как вы думаете, это потому, что компилятор не достаточно умный, или вы думаете, что есть реальная амбивалентность в моем выражении?
Этого слишком много, чтобы спросить. Помните, что классы типов * open *, что означает, что код должен продолжать компилироваться при добавлении новых экземпляров. Мы могли бы легко добавить экземпляр для 'O M', что сделало бы ваше выражение неоднозначным, и, следовательно, оно должно быть уже неоднозначным в открытом мире. Однако новые [закрытые типы семейств] (https://wiki.haskell.org/GHC/Type_families#Closed_family_simplification) могут делать то, что вы хотите - я не работал с ними много, поэтому я не могу быть уверен. – luqui
И на самом деле (используя 'FlexibleInstances') вы можете просто определить' x :: O M => K; x = f (o :: M) ', а затем используйте' x' в другом модуле, который имеет экземпляр O M. Поэтому в этом смысле выбор типа 'o' в выражении' f o' действительно неоднозначен. –
@ReidBarton, вы имеете в виду 'FlexibleContexts'? – dfeuer