Почему <*> экземпляра Const принимает два нефункциональных значения?
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Const :: a -> Const a b
Monoid m => Applicative (Const * m)
Const "a" <*> Const "b" -- yields Const "ab"
Const a <*> Const a = Const a <> Const a
Я предполагаю, что это поведение должно быть связано с тем, что Const
конструктор двоичного типа, где b
никогда не трогать (фантомный тип). Но опять же я не понимаю Const * m
, так как a
(а также *
соответственно) похоже отбрасывается в этом случае.
1 ответ
Сначала если m
имеет Monoid
экземпляр, то Const m
имеет Applicative
пример. Но Const m
все еще является конструктором типа, поэтому тип <*>
за Applicative (Const m)
читает
(<*>) :: Const m (a -> b) -> Const m a -> Const m b
Теперь давайте применим это к Const "a"
а также Const "b"
:
Const "a"
имеет тип Const String b
, Так вот переменная типа m
сверху предполагает тип String
, Значение по-прежнему полиморфно по отношению к b
и так как он не содержит конкретного значения этого типа, тип может быть любым.
В выражении Const "a" <*> Const "b"
полиморфное значение Const "a"
будет вынужден быть типа Const String (a->b)
и полиморфное значение Const "b"
будет вынужден быть типа Const String a
,
Таким образом, действительно есть тип с типом функции внутри с левой стороны, просто конкретное значение не содержит функции, как со значением Nothing
типа Maybe (Int -> Int)
,
PS: я не знаю, где *
приходит из Monoid m => Applicative (Const * m)
, Если я наберу
:info Const
в GHCI я понимаю
instance Monoid m => Applicative (Const m)