Doesn't tacit programming correspond pretty closely to combinator logic or pointless point-free style in Haskell? For instance, while I don't know J from what I gather a "fork" translates three functions f
, g
, and h
and an argument x
into an expression g (f x) (h x)
. The operation of "apply multiple functions to a single argument, then apply the results to each other in sequence" is a generalization of Curry's Schönfinkel's S combinator and in Haskell corresponds to the Applicative
instance of the Reader monad.
A fork
combinator in Haskell such that fork f g h x
matches the result specified above would have the type (t -> a) -> (a -> b -> c) -> (t -> b) -> t -> c
. Interpreting this as using the Reader functor ((->) t)
and rewriting it for an arbitrary functor, the type becomes f a -> (a -> b -> c) -> f b -> f c
. Swapping the first two arguments gives us (a -> b -> c) -> f a -> f b -> f c
, which is the type of liftA2
/liftM2
.
So for the common example of computing the average, the fork +/ % #
can be translated directly as flip liftA2 sum (/) (fromIntegral . length)
or, if one prefers the infix Applicative
combinators, as (/) <$> sum <*> fromIntegral . length
.
If not, is there a technical issue that makes this impossible, or is it just not worth doing?
In Haskell at least, I think the main issue is that extremely point-free style is considered obfuscated and unreadable, particularly when using the Reader monad to split arguments.