Применить полиморфную функцию к двум различным типам входов

Рассмотрим эту функцию:

doToBoth f x y = (f x, f y)

Работает как положено в простых случаях:

doToBoth (2 *) 10 15 == (20, 30)
doToBoth head [1,2] [3,4,5] == (1, 3)

Тогда я попробовал эти:

doToBoth head [1,10,100] "apple"
doToBoth pred 2 'b'

Я хочу, чтобы оба результата привели к (1, 'a'), но вместо этого они просто приводят к ошибке типа. Проблема в том, что предполагаемый тип doToBoth недостаточно полиморфен:

doToBoth :: (a1 -> a2) -> a1 -> a1 -> (a2, a2)

Видя это, я попытался добавить явную сигнатуру типа, чтобы исправить это:

doToBoth :: (t ~ (i1 -> o1), t ~ (i2 -> o2)) => t -> i1 -> i2 -> (o1, o2)

Этот тип подписи был принят, но это не решило проблему, и проверка того, что случилось с :t doToBoth обнаружил, что в итоге получился тип, эквивалентный исходному предполагаемому:

doToBoth :: (i2 -> o2) -> i2 -> i2 -> (o2, o2)

Как правильно написать сигнатуру типа, чтобы эта функция работала так, как я хочу?

1 ответ

Принятие полиморфного аргумента делает вашу функцию полиморфной ранга 2. GHC имеет расширение для этого, но вы можете использовать его, только если можете каким-то образом определить, какие типы типов должен поддерживать аргумент - с помощью конструкторов типов или классов. Например, для списков вы можете написать

{-# LANGUAGE Rank2Types, UnicodeSyntax #-}
doToBoth_listelem :: (∀ x . [x] -> x) -> [a] -> [b] -> (a,b)
doToBoth_listelem f x y = (f x, f y)
> doToBoth_listelem head [1,10,100] "apple"
(1,'a')

Это также будет работать для pred пример, и является несколько более полезным. В этом случае вам нужно количественно определить аргумент, который ограничен Enum учебный класс:

doToBoth_enum :: (Enum a, Enum b)
      => (∀ x . Enum x => x -> x) -> a -> b -> (a,b)
doToBoth_enum f x y = (f x, f y)
> doToBoth_enum pred 2 'b'
(1,'a')

Я думаю, что написать его так, чтобы он автоматически работал для любого такого ограничения, которое может потребоваться для аргумента, невозможно. Можно было бы приблизить это к некоторым умным семействам типов и типам ограничений, но я сомневаюсь, что в конечном итоге это будет практически применимо.

Другие вопросы по тегам