Это личное упражнение, чтобы понять пределы системы типа Haskell немного лучше. Я хочу создать самую общую функцию, которую я могу применить к каждой записи в 2-х входных кортежах, например:
applyToTuple fn (a,b) = (fn a, fn b)
Я пытаюсь заставить эту функцию работать в каждом из следующих случаев:
(1) applyToTuple length ([1,2,3] "hello")
(2) applyToTuple show ((2 :: Double), 'c')
(3) applyToTuple (+5) (10 :: Int, 2.3 :: Float)
Итак, для length
элементы в паре должны быть Foldable
, для показа они должны быть экземплярами Show
и т.д.
Используя RankNTypes
, я могу сделать некоторые пути, например:
{-# LANGUAGE RankNTypes #-}
applyToTupleFixed :: (forall t1. f t1 -> c) -> (f a, f b) -> (c, c)
applyToTupleFixed fn (a,b) = (fn a, fn b)
Это позволяет использовать функцию, которая может работать с общим контекстом f
для элементов в этом контексте. (1)
работает с этим, но элементы кортежа в (2)
и (3)
не имеют контекста, и поэтому они не работают (и в любом случае 3 возвращают разные типы). Я мог бы, конечно, определить контекст для размещения элементов, например:
data Sh a = Show a => Sh a
instance Show (Sh a) where show (Sh a) = show a
applyToTuple show (Sh (2 :: Double), Sh 'c')
чтобы получить другие примеры. Мне просто интересно, можно ли определить такую общую функцию в Haskell без необходимости обертывать элементы в кортежах или давать applyToTuple более конкретную подпись типа.