Function 函数算术?
整个夏天,我学习了一点PHP和javascript,所以我想今年我在数学方面也会领先一步,对我来说,这将是微积分。我在看一些视频时发现: 他说Function 函数算术?,function,functional-programming,Function,Functional Programming,整个夏天,我学习了一点PHP和javascript,所以我想今年我在数学方面也会领先一步,对我来说,这将是微积分。我在看一些视频时发现: 他说(f+g)(x)=f(x)+g(x)。我从未见过这样编写的函数,所以我想问一下这是否也是用编程语言实现的 假设我有,在伪代码中: function double(x){ return x*2; } function triple(x){ return x*3; } 是否有任何编程语言允许以下内容: (双+三)(10) …等于50 还有,有没有一个地方可
(f+g)(x)=f(x)+g(x)
。我从未见过这样编写的函数,所以我想问一下这是否也是用编程语言实现的
假设我有,在伪代码中:
function double(x){
return x*2;
}
function triple(x){
return x*3;
}
是否有任何编程语言允许以下内容:
(双+三)(10)
…等于50
还有,有没有一个地方可以让我从一个不到一万年的地方学习微积分
另外,我知道没有一种编程语言可以使用这种精确的语法,但我的意思是类似的…大多数语言都允许您以这样或那样的方式执行此操作
function add(a, b) {
return function(x) {
return a(x) + b(x);
};
}
add(double, triple)(10); // Gives 50
您可以在Scala中轻松做到这一点:
abstract class F { f =>
def apply(x: Double): Double
def +(g: F) = { new F { def apply(x: Double) = f(x) + g(x) } }
}
object F {
implicit def funcToF(f: Double => Double) = new F { def apply(x: Double) = f(x) }
}
import F.funcToF
val f = (x: Double) => 2*x
val g = (x: Double) => 3*x
val h = f + g
println(f(1)) // 2
println(g(1)) // 3
println(h(1)) // 5
println((f + g)(1)) // 5
您可以在How to do上在线试用
在Haskell中,这实际上非常简单:
Prelude Control.Monad> liftM2 (+) (* 2) (* 3) 10
50
或者,或者:
Prelude Control.Applicative> (+) <$> (* 2) <*> (* 3) $ 10
50
这里发生了什么事?如果你在PHP和JavaScript方面有经验的话,Haskell是一种非常陌生的语言,所以我将尝试将其分解。但请注意:这里的相关函数(liftM2
和
/
)比简单的使用要普遍得多,这可能会让您一开始很难理解它们。然而,由此产生的力量是值得的
高级别摘要 下面是我对一个非常高级的总结的尝试:
liftM2
接受一个二进制函数op
,并生成一个对“更复杂”的值进行操作的二进制函数。如果“更复杂”的值是单参数函数f
和g
,那么只有一种很好的方法可以组合它们并生成一个新的单参数函数:生成一个将其参数x
传递到f
和g
的函数,然后计算fx`op`gx
——它使用op
组合它们的结果。在JavaScript中,这类似于
function liftM2_functions(op) {
return function (f,g) {
return function (x) { op(f(x), g(x)) }
}
}
由于liftM2
仅适用于二进制函数,因此也有liftM3
适用于三元函数,等等,但这很混乱;因此,引入了
和
操作符,使得liftMn f a1 a2。。。a
完全等同于f a1 a2。。。一个
细节 如果你想得到更详细的答案,请继续阅读。我要警告你,我不知道这有多清楚;它依赖于一些我必须半手工保存的概念,我可能做得不好。但如果你是游戏玩家,我们开始吧 首先,让我们解释一些Haskell语法:
和(*2)
是书写(*3)
和\x->x*2
的简捷方法,它们只是JavaScript\x->x*3
和函数(x){return x*2}
的Haskell函数(x){return x*3}
只是执行加法的函数;它是中缀运算符(+)
的前缀形式+
是函数应用程序fx
f(x)
被解析为fxy
,但可以被视为双参数函数应用程序(fx)y
f(x,y)
中缀运算符也是函数应用程序,但优先级较低:$
被解析为..$x
(…)x
和
是奇特的中缀运算符
liftM2(+)(*2)(*3)10
中,您想要的“函数添加函数”是liftM2(+)
;它的两个参数是(*2)
和(*3)
;结果的参数是10
。发生什么事?在Haskell中,正确的思考方式是从类型的角度来考虑。以下是相关类型,但请注意,您可能无法立即理解它们
liftM2 :: Monad m => (a -> b -> r) -> m a -> m b -> m r
(+) :: Num a => a -> a -> a
(* 2) :: Num a => a -> a
(* 3) :: Num a => a -> a
10 :: Num a => a
这里,f::t
表示“f
具有类型t
”。这些类型非常抽象,所以让我们简化一些事情。当您看到numa
时,它的意思是“对于某个类型a
,它是一个数字”;例如,我们可以将其视为Int
或Double
。所以这给了我们
(+) :: Int -> Int -> Int
(* 2) :: Int -> Int
(* 3) :: Int -> Int
10 :: Int
好的,10
是一个整数。那么(*2)
和(*3)
呢?这些函数由->
表示,将整数映射为整数。您知道(+)
是一个整数上的二进制函数,因此您可能会认为它的类型是(Int,Int)->Int
。然而,在Haskell中,正确的方法是将其看作一个函数,它接受一个整数并返回另一个函数;这叫做咖喱。在JavaScript中,这将实现为
function add(x) {
return function (y) {
return x + y
}
}
// Usage: add(10)(11) = 21.
你可能不明白为什么这是好的,但它将成为相关的一点
现在,让我们来处理liftM2::Monad m=>(a->b->r)->ma->mb->mr
。这到底是怎么回事?忽略Monad m
位,这表示liftM2
采用一个双参数函数,一个“monadica
”和一个“monadicb
”,并生成一个“monadicr
”。不过,多亏了curry,这就等于说liftM2
接受一个双参数函数并返回一个双参数函数,其参数和结果是一元的:liftM2::Monad m=>(a->b->r)->(ma->mb->mr)
。这就是这里发生的:liftM2(+)
是加法的一元版本
单子(不要惊慌!)
现在,我一直使用单子这个词,但我还没有定义它。我不打算!网上有很多monad教程,有些甚至不错;如果你好奇的话,去看看吧。现在你需要了解的是:一元值是一个以某种方式“增加”的值,通过有一些
function add(x) {
return function (y) {
return x + y
}
}
// Usage: add(10)(11) = 21.
liftM2 :: (a -> b -> r) -> ((e -> a) -> (e -> b) -> (e -> r))
liftM2 (+) :: (e -> Int) -> (e -> Int) -> (e -> Int)
liftM2 f m1 m2 = do x1 <- m1
x2 <- m2
return $ f x1 x2
do doubled <- (* 2)
tripled <- (* 3)
return $ doubled + tripled
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> val double = (x: Int) => 2 * x
double: (Int) => Int = <function1>
scala> val triple = (x: Int) => 3 * x
triple: (Int) => Int = <function1>
scala> val h = (double |@| triple) { _ + _ }
h: (Int) => Int = <function1>
scala> h(10)
res13: Int = 50