С вашей типизацией это невозможно, потому что ваш f = fst
является полиморфным, и два вызова неявно связаны с другим типом.Если мы сделаем вызовы явными, они станут:
fst @ (Int,Int) (fst @ ((Int,Int),Int) ((1,2),3))
Можно было бы использовать другой тип для twice
, требуя, чтобы аргумент был полиморфной функцией.Для этого требуется Rank2Types
:
twice' :: (forall a b . (a, b) -> a) -> ((a,b),c) -> a
twice' f x = f ( f x )
Однако вышеприведенная функция имеет ограниченное использование, поскольку единственным значимым выбором для f
является fst
- других завершающих функций типа * 1012 нет.*.
Также должна быть возможность использовать классы типов, включая несколько расширений.
class C a where
type Res a
theF :: a -> Res a
instance C (a, b) where
type Res (a, b) = a
theF = fst
twiceC :: (C a, C (Res a)) => a -> Res (Res a)
twiceC x = theF (theF x)
Здесь, однако, функция должна быть определена в instance
, вместопередачи в качестве параметра.