ali*_*62b 14 f# functional-programming currying
我想知道这对F#意味着什么.
"一个取整数的函数,
它返回一个取整数并返回一个整数的函数."
但我对此并不了解.
有人能解释清楚这个吗?
[更新]:
> let f1 x y = x+y ;;
val f1 : int -> int -> int
Run Code Online (Sandbox Code Playgroud)
这是什么意思 ?
Bru*_*eis 57
让我们从头开始.
F#使用冒号(:)表示法来指示事物的类型.假设你定义了一个类型的值int:
let myNumber = 5
Run Code Online (Sandbox Code Playgroud)
F#Interactive会理解这myNumber是一个整数,并会通过以下方式告诉你:
myNumber : int
Run Code Online (Sandbox Code Playgroud)
读作的是
myNumber是类型的int
到现在为止还挺好.让我们介绍一些其他功能类型.功能性类型仅仅是一个函数的类型.F#用于->表示功能类型.这个箭头象征着在左手边写的东西被转换成写在右手边的东西.
让我们考虑一个简单的函数,它接受一个参数并将其转换为一个输出.这种功能的一个例子是:
isEven : int -> bool
Run Code Online (Sandbox Code Playgroud)
这将介绍函数的名称(在左侧:)及其类型.这行可以用英文阅读:
isEven是一个int将函数转换为a 的类型函数bool.
请注意,要正确解释所说的内容,您应该在"类型"部分之后进行短暂停顿,然后立即读取句子的其余部分,而不会暂停.
在F#中,函数(几乎)不比普通类型更特殊.它们是你可以传递给函数的东西,从函数返回,就像bool,int或字符串一样.
所以如果你有:
myNumber : int
isEven : int -> bool
Run Code Online (Sandbox Code Playgroud)
您应该考虑int和int -> bool作为同一类型的两个实体:类型.这里,myNumber是类型的值int,并且isEven是类型的值int -> bool(这是我想,当我谈论的象征短暂停顿以上).
包含的类型的值->恰好也称为函数,并具有特殊功能:您可以将函数应用于值.所以,例如,
isEven myNumber
Run Code Online (Sandbox Code Playgroud)
意味着您正在将所调用的函数isEven应用于该值myNumber.正如您所期望的那样,通过检查类型isEven,它将返回一个布尔值.如果你已经正确实施isEven,它显然会返回false.
让我们定义一个泛型函数来确定一个整数是其他整数的倍数.我们可以想象我们的函数的类型将是(括号在这里是为了帮助你理解,它们可能存在也可能不存在,它们具有特殊含义):
isMultipleOf : int -> (int -> bool)
Run Code Online (Sandbox Code Playgroud)
你可以猜到,这被解读为:
isMultipleOf是一种类型(PAUSE)函数,它将转换int为(PAUSE)函数转换int为abool.
(此处(PAUSE)表示大声朗读时的暂停).
我们稍后会定义这个函数.在此之前,让我们看看我们如何使用它:
let isEven = isMultipleOf 2
Run Code Online (Sandbox Code Playgroud)
F#interactive会回答:
isEven : int -> bool
Run Code Online (Sandbox Code Playgroud)
读作的是
isEven是类型的int -> bool
这里isEven有类型int -> bool,因为我们刚刚给出了值2(int)isMultipleOf,正如我们已经看到的那样,它转换int成了一个int -> bool.
我们可以将此函数isMultipleOf视为一种函数创建者.
isMultipleOf所以现在我们来定义这个神秘的函数创建函数.
let isMultipleOf n x =
(x % n) = 0
Run Code Online (Sandbox Code Playgroud)
好吗,对吧?
如果您在F#Interactive中输入此内容,它将回答:
isMultipleOf : int -> int -> bool
Run Code Online (Sandbox Code Playgroud)
请注意,没有括号.这对你来说并不是特别重要.请记住,箭头是正确的关联.也就是说,如果你有
a -> b -> c
Run Code Online (Sandbox Code Playgroud)
你应该把它解释为
a -> (b -> c)
Run Code Online (Sandbox Code Playgroud)
在右侧的右结合意味着你应该解释为,如果有各地最右边括号操作.所以:
a -> b -> c -> d
Run Code Online (Sandbox Code Playgroud)
应该被解释为
a -> (b -> (c -> d))
Run Code Online (Sandbox Code Playgroud)
isMultipleOf所以,正如您所见,我们可以isMultipleOf用来创建新功能:
let isEven = isMultipleOf 2
let isOdd = not << isEven
let isMultipleOfThree = isMultipleOf 3
let endsWithZero = isMultipleOf 10
Run Code Online (Sandbox Code Playgroud)
F#Interactive会回复:
isEven : int -> bool
isOdd : int -> bool
isMultipleOfThree : int -> bool
endsWithZero : int -> bool
Run Code Online (Sandbox Code Playgroud)
但你可以用不同的方式.如果您不想(或需要)创建新函数,可以按如下方式使用它:
isMultipleOf 10 150
Run Code Online (Sandbox Code Playgroud)
这将返回true,因为150是10的倍数.这与创建函数endsWithZero然后将其应用于值150 完全相同.
实际上,函数应用程序是左关联的,这意味着上面的行应解释为:
(isMultipleOf 10) 150
Run Code Online (Sandbox Code Playgroud)
也就是说,将括号括在最左边的函数应用程序周围.
现在,如果你能理解这一切,你的例子(这是规范的CreateAdder)应该是微不足道的!
前段时间有人问这个问题涉及完全相同的概念,但是在Javascript中.在我的回答中,我给出了两个规范的例子(CreateAdder,CreateMultiplier)inf Javascript,它们对返回函数更加明确.
我希望这有帮助.
这个典型的例子可能是"加法器创建者" - 一个函数,给定一个数字(例如3)返回另一个函数,该函数取一个整数并将第一个数字加到它上面.
因此,例如,在伪代码中
x = CreateAdder(3)
x(5) // returns 8
x(10) // returns 13
CreateAdder(20)(30) // returns 50
Run Code Online (Sandbox Code Playgroud)
我不太习惯在F#中试着写它而不检查它,但C#会是这样的:
public static Func<int, int> CreateAdder(int amountToAdd)
{
return x => x + amountToAdd;
}
Run Code Online (Sandbox Code Playgroud)
这有帮助吗?
编辑:正如布鲁诺所说,你在问题中给出的例子就是我给出C#代码的例子,所以上面的伪代码将成为:
let x = f1 3
x 5 // Result: 8
x 10 // Result: 13
f1 20 30 // Result: 50
Run Code Online (Sandbox Code Playgroud)
它是一个函数,它接受一个整数并返回一个取整数并返回一个整数的函数.
这在功能上等效于一个带有两个整数并返回整数的函数.这种处理带有多个参数的函数的方法在函数式语言中很常见,并且可以很容易地在函数上部分应用函数.
例如,假设有一个add函数,它接受两个整数并将它们加在一起:
let add x y = x + y
Run Code Online (Sandbox Code Playgroud)
您有一个列表,并且您想要为每个项目添加10.您将add函数部分应用于该值10.它会将其中一个参数绑定到10并使另一个参数保持未绑定状态.
let list = [1;2;3;4]
let listPlusTen = List.map (add 10)
Run Code Online (Sandbox Code Playgroud)
这个技巧使编写功能非常容易,并使它们非常可重用.如您所见,您不需要编写另一个向列表项添加10以将其传递给的函数map.你刚刚重用了这个add功能.