KJ5*_*J50 11 haskell pointfree
我试图了解如何在Haskell中将函数转换为无点表示法.我看到了这个例子,但它比我想要的更复杂.我觉得我理解它背后的逻辑,但当我试图在代码中执行一些简单的例子时,我得到了编译错误.我想尝试以无点样式编写此函数:
f x = 5 + 8/x 我重新安排为 f x = (+) 5 $ (/) 8 x
所以,我认为它可能是这样的:
f = (+) 5 $ (/) 8
Run Code Online (Sandbox Code Playgroud)
但是当我在ghci中运行时,我得到这样的信息:
No instance for (Num (a0 -> a0))
arising from the literal `5' at Test.hs:3:9
Possible fix: add an instance declaration for (Num (a0 -> a0))
In the first argument of `(+)', namely `5'
In the first argument of `($)', namely `(+) 5'
In the expression: (+) 5 $ (/) 8
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
我不明白"没有实例......"的信息.以无点样式编写此函数需要做什么?
Pra*_*eek 17
$优先级很低.所以,f x = (+) 5 $ (/) 8 x实际上意味着f x = (+) 5 $ ((/) 8 x).相反,重写为
f x = (+) 5 ( (/) 8 x)
f x = ((+) 5) ( ((/) 8) x)
f x = ((+) 5) . ( ((/) 8) ) x
f = ((+) 5) . ( (/) 8 )
f = (5+) . (8/)
Run Code Online (Sandbox Code Playgroud)
最后一个表达式是有意义的:f是两个操作的组合,首先将8除以其中的一个,然后将5添加到结果中.记住,g.h意思是"应用h,然后应用g的结果".
dfl*_*str 11
"pointfree"程序可以安装cabal install pointfree,并向您展示如何以无点样式编写表达式.例如:
$ pointfree "f x = 5 + 8/x"
f = (5 +) . (8 /)
Run Code Online (Sandbox Code Playgroud)
此转换的说明:
(a +) == \b -> a + b和(+ a) == \b -> b + a.函数获取第二个参数的结果,该参数是单参数函数,并将其应用于第一个参数.Rot*_*sor 11
从lambda演算(Haskell是其变体)到SKI术语(完全无点函数,仅使用const(K),id(I)和<*>(S))的转换可以使用以下简单规则完成:
\x -> x翻译成id;\x -> y没有x发生y翻译const y;\x -> f g转换到f' <*> g'哪里
f'是的翻译\x -> f和g'是一个翻译\x -> g.现在你可能想知道它是.从哪里进来的.最后一个翻译有一个特殊情况:如果f没有任何自由出现x,则\x -> f g转换const f <*> (\x -> g)为等于f . (\x -> g).
使用这些规则我们可以转换您的功能:
f = \x -> ((+) 5) (((/) 8) x) = -- by the special-case (.) rule
((+) 5) . (\x -> (((/) 8) x)) = -- by eta-reduction ((\x -> f x) = f)
((+) 5) . ((/) 8)
Run Code Online (Sandbox Code Playgroud)
完成翻译不需要减少Eta,但如果没有它,我们就会变得更加混乱.例如,最后一步将产生((+) 5) . ((/) 8) . id.
你真的很亲近 请允许我再添加一个$来说明:
f x = (+) 5 $ (/) 8 $ x
Run Code Online (Sandbox Code Playgroud)
应该清楚的是,表达式(+) 5是一个接受一个数字输入并产生一个数字输出的函数。表达式也是如此(/) 8。因此,无论输入什么数字,您都应x先应用(/) 8“函数”,然后再应用(+) 5“函数”。
只要您有一连串的功能被分隔$,就可以用.Meaning 替换除最右边的所有功能,如果有的话a $ b $ c $ d,则等效于a . b . c $ d。
f x = (+) 5 . (/) 8 $ x
Run Code Online (Sandbox Code Playgroud)
在这一点上,我们实际上是除去了$和圆括号来代替。
f x = ((+) 5 . (/) 8) x
Run Code Online (Sandbox Code Playgroud)
现在应该很清楚,您可以x从两侧删除尾部:
f = (+) 5 . (/) 8
Run Code Online (Sandbox Code Playgroud)
这是主要思想。如果有的话f x = expr x,可以将它“减少”为f = expr。为了产生无点代码,您只需要简单地认识到较大的函数是由较小的函数组成的。部分应用程序有时需要对点自由码(如在这种情况下,(+) 5与(/) 8部分地施加)。当您不想考虑时,“ pointfree”程序非常有用。#haskell irc频道上的Lambdabot使用此程序作为插件,因此您甚至不必自己安装它。只是问:
<DanBurton> @pl let f x = 5 + 8 / x in f
<lambdabot> (5 +) . (8 /)
Run Code Online (Sandbox Code Playgroud)