Начиная с ghc-8.0 у нас есть очень хорошее расширение под названием TypeApplications
.Что позволяет нам вместо:
λ> show (5 :: Int)
"5"
сделать что-то вроде этого:
λ> :set -XTypeApplications
λ> show @Int 5
"5"
Что действительно круто.Это становится немного сложнее, когда мы добавляем больше переменных типа, но есть правила, которые можно использовать для определения точного порядка, и они очень хорошо документированы:
showFooBar :: (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b
Так что в приведенной выше функции мы бысначала поставьте a
, а затем b
:
λ> showFooBar @Int @Double 3 4
"3 and 4.0"
Отлично, но что если я бы хотел изменить порядок?Нет проблем, мы можем использовать расширение ExplicitForAll
(или другое, которое подразумевает его), чтобы указать его:
{-# LANGUAGE ExplicitForAll #-}
showFooBar :: forall b a . (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b
И теперь мы изменили порядок типов, которые мы собираемся применить:
λ> showFooBar @Int @Double 3 4
"3.0 and 4"
Проблема в том, что я не могу понять, как добиться того же эффекта для функций, которые являются частью класса типов.Рассмотрим следующий пример:
{-# LANGUAGE MultiParamTypeClasses #-}
class (Show a, Show b) => FooBar a b where
fooBarClassFunc :: a -> b -> String
Я не могу поставить forall
для функции сейчас (например, fooBarClassFunc :: forall a b . a -> b -> ..
, потому что это меняет смысл функции и, очевидно, не компилируется.
Итак, вопрос в том, как изменить порядок переменных типа с целью TypeApplication
внутри методов класса типов?
Редактировать
Простов данном случае я пробовал расширение InstanceSigs
, и оно полностью игнорирует порядок переменных типа forall
, что касается TypeApplications
, что хорошо, в противном случае мы бы в конечном итоге получили поведение, определяемоеэкземпляр, а не класс.