我试图了解如何在Haskell中将函数转换为无点表示法。我看到this example,但它比我想要的更复杂。我觉得我理解它背后的逻辑,但当我试图在代码中执行一些简单的例子时,我得到了编译错误。我想尝试以无点样式编写这个函数:
f x = 5 + 8/x
我将其重新排列为f x = (+) 5 $ (/) 8 x
所以,我认为它可能是这样的:
f = (+) 5 $ (/) 8
但是当我在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.
我不明白“没有实例......”的信息。如何以无点样式编写此函数需要做什么?
答案 0 :(得分: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/)
最后一个表达式是有意义的:f是两个操作的组合,首先将8除以其中的一个,然后将5添加到结果中。请记住,g.h
表示“应用h,然后应用g的结果”。
答案 1 :(得分:11)
“pointfree”程序可以与cabal install pointfree
一起安装,并向您展示如何以无点样式编写表达式。例如:
$ pointfree "f x = 5 + 8/x"
f = (5 +) . (8 /)
此转换的说明:
(a +) == \b -> a + b
和(+ a) == \b -> b + a
.
函数获取第二个参数的结果,该参数是单参数函数,并将其应用于第一个参数。答案 2 :(得分:11)
从lambda演算(Haskell是其变体)转换为SKI术语(完全无点函数,仅使用const
( K ),id
(< strong>我)和<*>
( S ))可以使用以下简单规则完成:
\x -> x
转换为id
; \x -> y
中没有x
的{li> y
转换为const y
;
\x -> f g
转换为f' <*> g'
其中
f'
是\x -> f
和g'
是\x -> g
。现在你可能想知道.
在哪里进来了。最后一个翻译有一个特例:如果f
没有任何x
的自由出现,那么{{ 1}}转换为\x -> f g
,等于const f <*> (\x -> g)
。
使用这些规则我们可以转换您的功能:
f . (\x -> g)
Eta-reduction不是完成翻译所必需的,但如果没有它,我们就会变得更加混乱。例如,最后一步将产生f = \x -> ((+) 5) (((/) 8) x) = -- by the special-case (.) rule
((+) 5) . (\x -> (((/) 8) x)) = -- by eta-reduction ((\x -> f x) = f)
((+) 5) . ((/) 8)
。
答案 3 :(得分:4)
你真的很亲密。请允许我再添加一个$
来说明:
f x = (+) 5 $ (/) 8 $ x
应该很清楚,表达式(+) 5
是一个函数,它接受一个数字输入并产生一个数字输出。表达式(/) 8
也是如此。因此,您输入任意数字x
,然后首先应用(/) 8
“函数”,然后应用(+) 5
“函数”。
每当你有一串由$
分隔的函数时,你可以用.
意义替换除最右边的所有函数,如果你有a $ b $ c $ d
,这相当于a . b . c $ d
}。
f x = (+) 5 . (/) 8 $ x
此时,让我们实际上删除 $
并改为括号。
f x = ((+) 5 . (/) 8) x
现在应该清楚的是,您可以从双方删除尾随的x
:
f = (+) 5 . (/) 8
是主要想法。如果您有f x = expr x
,则可以将其“减少”到f = expr
。为了生成无点代码,您只需要识别较大的函数如何由较小的函数组成。对于无点代码,有时需要部分应用(在这种情况下,部分应用(+) 5
和(/) 8
)。当您不想考虑它时,“免费”程序非常有用; #haskell irc频道上的Lambdabot将此程序用作插件,因此您甚至不必自己安装它;请问:
<DanBurton> @pl let f x = 5 + 8 / x in f
<lambdabot> (5 +) . (8 /)