点免费功能能够内联吗?

时间:2012-09-20 22:38:46

标签: f# inline currying pointfree

let inline myfunction x y = ...

let inline mycurried = myfunction x // error, only functions may be marked inline

似乎不可能明确inline curried函数。 因此,只要mycurried被调用,即使inlined myfunction正确inlined,它也不会得到{{1}},是否正确?

那么这可以被视为咖喱功能的缺点之一吗?

3 个答案:

答案 0 :(得分:5)

我认为您的问题是point-free函数是否可以内联。

您发现的限制不是因为咖喱功能。 请注意,在您的示例中,curried函数位于右侧,在左侧,您具有无点函数。

F#只允许函数内联,而不是常量。

我原则你可能认为这可以被视为一个错误,因为类型推断足够聪明,可以发现这是一个(无点)函数,但是阅读Tomas关于副作用的注释。

显然,当编译器在左侧只找到一个标识符时,它会因此错误而失败:

let inline myfunction x y = x + y

let inline mycurried  = myfunction 1

--> Only functions may be marked 'inline'

正如Brian所说,解决方法是在双方都添加一个明确的参数:

let inline mycurried x  = (myfunction 1) x

但是你的功能不再是无点的,它与:

相同
let inline mycurried x  = myfunction 1 x

另一种方法可能是添加一个显式的通用参数:

let inline mycurried<'a>  = myfunction 1

当通用参数明确显示在左侧时,它会编译。

我希望他们删除错误消息并将其发出警告,例如:

Since only functions can be 'inline' this value will be compiled as a function.

<强>更新

感谢Tomas的回答(和你的downvote)。

我个人认为这应该是一个警告,所以你知道你的代码的语义最终会改变,但是由你来决定做什么。

你说内联是“只是一个优化”但这并不完全正确:

。简单地内联所有功能并不能保证最佳代码。

。您可能希望使用静态约束,然后必须使用内联。

我希望能够定义我的(种类)通用常量,因为F#库已经存在(即:GenericZero和GenericOne)。我知道我的代码是纯粹的,所以我不在乎每次都执行它。

答案 1 :(得分:4)

我认为你只需要向双方添加一个显式参数(虽然我还没试过):

let inline myfunction x y = ... 

let inline mycurried y = myfunction 42 y  // or whatever value (42)

答案 2 :(得分:2)

编译器只允许inline定义一个函数的let绑定。这与发生的事情基本相同with F# value restriction(并参见also here)。正如Brian所说,您可以通过向函数添加参数来轻松解决此问题。

为什么存在这种限制?如果它不存在,那么添加inline会改变你的程序的含义,那会很糟糕!

例如,假设您有一个这样的函数(它创建可变状态并返回计数器函数):

let createCounter n = 
  let state = ref n
  (fun () -> incr state; !state)

现在,以下代码:

let counter = createCounter 0

...创建一个可以多次使用的单个全局函数(调用counter()),它将从1开始为您提供唯一的整数。如果您可以将其标记为inline

let inline counter = createCounter 0

...然后每次使用counter()时,编译器都应将其替换为createCounter 0 (),因此每次调用计数器时都会得到1!