Или, скорее, какой самый идиоматичный способ сделать это в Haskell?
Идиоматические? Если вам действительно нужна функция, которая делает то, что делает ($$$)
, то ваш код, вероятно, настолько же идиоматичен, насколько и вы.
Я бы предпочел увидеть какой-нибудь хитрый трюк
О, хорошо, в этом случае.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE UndecidableInstances #-}
class ListApply f a r | f -> a r where
($...) :: f -> [a] -> r
instance (TypeCast b r) => ListApply b a r where
x $... _ = typeCast x
instance (ListApply f a r) => ListApply (a -> f) a r where
f $... (x:xs) = (f x) $... xs
Итак, полностью общее решение: учитывая функцию произвольной арности с такой сигнатурой, как a -> a ... -> b
, примените ее к стольким элементам списка [a]
, сколько необходимо. Демонстрация:
ones :: [Int]
ones = repeat 1
test1 x = x
test2 x y = x + y
test3 x y z = (x + z) * (y + z)
В GHCi:
> test1 $... ones
1
> test2 $... ones
2
> test3 $... ones
4
Я непременно приму "никогда не делай этого в реальном коде", если это лучший ответ
Вы, вероятно, хотите пойти с этим.
Да, и немного шаблонного кода, необходимого для запуска приведенного выше кода:
class TypeCast a b | a -> b, b->a where typeCast :: a -> b
class TypeCast' t a b | t a -> b, t b -> a where typeCast' :: t->a->b
class TypeCast'' t a b | t a -> b, t b -> a where typeCast'' :: t->a->b
instance TypeCast' () a b => TypeCast a b where typeCast x = typeCast' () x
instance TypeCast'' t a b => TypeCast' t a b where typeCast' = typeCast''
instance TypeCast'' () a a where typeCast'' _ x = x
Это швейцарский армейский нож метапрограммирования на уровне типов, любезно предоставленный Олег Киселев .