Ссылочная прозрачность полиморфных функций - PullRequest
7 голосов
/ 19 марта 2019

рассмотрим эту реализацию on

on f g = curry $ (. bimap g g) $ uncurry f

Что это за тип?GHC скажет (b -> b -> c) -> (a -> b) -> a -> a -> c, и это хорошее предположение.Но он пропускает экземпляр on (+) toInteger.Попробуем исправить это (используя RankNTypes, KindSignatures, AllowAmbiguousTypes и ConstraintKinds):

on :: forall (co :: * -> Constraint) a1 a2 b c . 
      (co a1, co a2) => 
      (b -> b -> c) 
   -> (forall a . co a => a -> b)
   -> a1 -> a2 -> c

И эта проверка типов.Но когда мы пытаемся

> :t (+) `on` toInteger

Мы получаем

• Couldn't match type ‘c’ with ‘Integer’
    ‘c’ is untouchable
      inside the constraints: co a
      bound by a type expected by the context:
                 forall a. co a => a -> c
      at <interactive>:1:1-18
  ‘c’ is a rigid type variable bound by
    the inferred type of it :: (co a1, co a2, Num c) => a1 -> a2 -> c
    at <interactive>:1:1
  Possible fix: add a type signature for ‘it’
  Expected type: a -> c
    Actual type: a -> Integer
• In the second argument of ‘on’, namely ‘toInteger’
  In the expression: (+) `on` toInteger

Так что это значит?

...