主流函数式编程语言中是否有通过库来模拟J风格的副词、分叉等功能?

25

是否曾经尝试使用类似动词、副词、分支等方式来模拟J语言中超级紧凑的暗示性编程风格,并通过主流函数式编程语言的库实现?

如果有的话,结果如何?

如果没有,是有技术问题使其不可能,还是因为不值得这样做?

我特别感兴趣的是像forks这样的结构,它们似乎并不直接对应于函数式编程中的基本概念。


1
我不知道,但我喜欢这个问题! - J D
2个回答

12
隐式编程与组合逻辑或Haskell中的无点风格非常相似,例如,虽然我不了解J语言,但据我所知,“fork”可以将三个函数f、g和h以及一个参数x转换为表达式g(f x)(h x)。将多个函数应用于单个参数,然后按顺序将结果应用于彼此的操作是Curry's Schönfinkel的S组合子的一般化,在Haskell中对应于Reader单子的Applicative实例。
在Haskell中,如果有一个“fork”组合子,使得fork f g h x匹配上述指定的结果,则其类型应为(t -> a) -> (a -> b -> c) -> (t -> b) -> t -> c。将其解释为使用Reader函子((->)t),并重写为任意函子,该类型变为f a -> (a -> b -> c) -> f b -> f c。交换前两个参数,得到(a -> b -> c) -> f a -> f b -> f c,这是liftA2/liftM2的类型。
因此,对于计算平均值的常见示例,fork +/ % #可以直接翻译为flip liftA2 sum (/) (fromIntegral . length),或者,如果更喜欢中缀Applicative组合器,则可以翻译为(/) <$> sum <*> fromIntegral . length。
至少在Haskell中,我认为主要问题在于极度无点风格被认为是混淆和不可读的,特别是在使用Reader单子拆分参数时。

9
略带沮丧的是,这篇回答中第二句话说:“...虽然我不懂J语言...”,但它为我在j标签下的回答中获得了第二高的点赞数。SO需要更多的J语言程序员! - C. A. McCann
1
此外,这个问题现在在J标签中拥有最多的赞。而且,我实际上从未编写和执行过J程序。不过我了解它 - 实际上我在1995年曾在多伦多的Ken Inverson家住了一个周末(当时我父亲正在与Ken一起工作J相关的事情,而我正在CMU攻读博士学位 - 是的,我想我是第二代PLer)。 - RD1
顺便说一句 - 很好的回答。我也是这么想的,但你表达得更好。一个区别是在 J 中,fork 在语法上是隐式的,hook 也是如此。我怀疑这种情况无法模拟,并且个人认为隐式 fork 和 hook 看起来有些过头了。另一个区别是 sclv 提到的实现 - J 实际上可以高效地处理大型(甚至巨大)数组。 - RD1
2
@RD1:使用恐怖的类型元编程技巧可以使一些东西更加隐晦,类似于编写多态函数的技巧,但这仍然不是同样的,并且会使实际编写“动作词”更加痛苦。通过一些模板Haskell/引用魔法捕捉那种正宗的Iverson-Backus风味可能是可行的,而且作为奖励,TH也可以执行一些融合优化等来提高效率。但此时你几乎没有在编写Haskell了... - C. A. McCann
1
请参考麦克布赖德的She预处理器中的习语括号,以了解应用程序样式:http://personal.cis.strath.ac.uk/~conor/pub/she/idiom.html(顺便说一句,这应该能让你编写*非常*漂亮的解析器)。 - sclv

8

Camccann的讨论非常好。但请注意,这种风格现在会导致两次遍历。

您可以编写一个组合器库来合并遍历。请参见此处: http://squing.blogspot.com/2008/11/beautiful-folding.html

该文章提供了编写均值的以下示例:

meanF :: Fractional a => Fold a a
meanF = bothWith (/) sumF (after lengthF fromIntegral)

mean :: Fractional a => [a] -> a
mean = cfoldl' meanF

此外,Conal Eliott的后续文章进一步推广了这个想法:http://conal.net/blog/posts/enhancing-a-zip/。他将代码从文章中提取出来,制作成一个库,并发布在hackage上:http://hackage.haskell.org/package/ZipFold

1
+1 -- 我确实只是在谈论风格,而不是实现。实际上使其实用化存在许多问题,其中大部分可以构建为递归组合器库。有关相关概念,请参见“流融合”。 - C. A. McCann
非常有趣 - 这确实似乎模拟了 J 解释器所做的一些事情。如果以克制的方式使用,它们可以导致相当优雅的代码。有没有想法这些想法在实践中有多受欢迎? - RD1
意思是:mean lst = lst |> dup (sum, length) |> uncurry (div),其中dup (f1, f2) = \x -> (f1 x,f2 x),a |> f = f a - aoeu256

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接