我正在学习Haskell。非常抱歉问一个非常基础的问题,但我似乎找不到答案。我有一个由以下方式定义的函数f:
f x = g x x
如何以点式风格编写已定义了两个参数的函数g?
编辑: 不使用lambda表达式。
谢谢。
f
可以用 Control.Monad.join
来表示:
f = join g
join
函数单子是构造无输入表达式时使用的原语之一,因为它本身无法以无输入方式定义(它在SKI演算中等价于。SII
——在Haskell中是ap id id
——但其类型不适用)
import Control.Monad
import Control.Monad.Instances
import Control.Applicative
f = join g -- = Wg (also, join = (id =<<))
= (g `ap` id) -- \x -> g x (id x) = SgI
= (<*> id) g -- = CSIg
= g =<< id -- \x -> g (id x) x
= id =<< g -- \x -> id (g x) x
S,K,I是一个基本的组合子集合;B,C,K,W则是另一个——你必须在某个地方停下来(关于你的“无lambda表达式”评论):
_B = (.) -- _B f g x = f (g x) = S(KS)K
_C = flip -- _C f x y = f y x = S(S(K(S(KS)K))S)(KK)
_K = const -- _K x y = x
_W = join -- _W f x = f x x = CSI = SS(KI) = SS(SK)
_S = ap -- _S f g x = f x (g x) = B(B(BW)C)(BB) = B(BW)(BBC)
= (<*>) -- from Control.Applicative
_I = id -- _I x = x = WK = SKK = SKS = SK(...)
{-
Wgx = gxx
= SgIx = CSIgx
= Sg(KIg)x = SS(KI)gx
= gx(Kx(gx)) = gx(SKgx) = Sg(SKg)x = SS(SK)gx
-- _W (,) 5 = (5,5)
-- _S _I _I x = x x = _omega x -- self-application, untypeable
-}
ι
(iota)组合子 - λf.fSK
,然后 SKI
表示为 S = ι(ι(ι(ιι)))
,K = ι(ι(ιι))
和 I = ιι
。这个基础对于简单类型的 λ-演算来说并不友好,ιι
甚至无法通过类型检查。U = λf.fKSK
更好一些(我不知道它是否有名称,所以我只是称之为通用的 U
);S = U(UU)
和 K = UUU
。 - Vitusf = g =<< id = id =<< g
。 - Will Ness我是偶然来到这里的,我想提供我的解决方案,因为在这个帖子中还没有人明确提到举升。
这是一个解决方案:
f = liftM2 g id id
g
的类型为 a -> a -> b
,即它接受 某种类型的两个值(必须是相同类型,否则 OP 给出的 f
的定义就没有意义),并返回另一个某种类型的值(不一定与参数类型相同);
lift2M g
是 g
的提升版本,类型为 (Monad m) => m a -> m a -> m b
:它接受 两个单子值,每个值都处于到目前为止未指定的上下文中,并返回一个单子值;
当将两个函数传递给 liftM2 g
时,掷骰子决定了 Monad
的上下文:这意味着值尚未存在其中,但在函数接收所需参数时将会存在;换句话说,函数是存储其自身未来值的单子;因此,lift2M g
接受两个函数(或两个函数的未来值),并返回另一个函数(或其未来值);知道这一点后,如果将 m
更改为 (->) r
或 r ->
,则其类型与上面相同:(r -> a) -> (r -> a) -> (r -> b)
我们传递的两个函数都是 id
,它保证会返回接收到的相同值;
因此,liftM2 g id id
是一个类型为 r -> b
的函数,它将其参数传递给这两个 id
,让其不变并将其转发给 g
。
f = g <$> id <*> id
liftA2
,对于函数来说与 liftM2
相同(即 Reader monad):liftA2 k f g x = k (f x) (g x)
。(刚刚发布:liftA2 (,) === (&&&)
:) )。 - Will Nessg <$> x <*> y
=== liftA2 g x y
,根据我记得的定义差不多是这样的。 - Will Ness
f = join g
。 - dflemstrjoin
是无点风格的原语,因为将SII
翻译成Haskell时,ap id id
是无效的——它有一个类型错误(具体来说,它未通过出现检查)。在SKI组合子演算中,它可以工作,因为它是无类型的。 - ehirdghci
中,Control.Monad.join (+)
会出现错误:No instance for (Monad ((->) a0)) arising from a use of
join' Possible fix: add an instance declaration for (Monad ((->) a0))。(我看到Control.Monad haddock有
instance Monad ((->) r)`,但没有相应的源代码(因为它在GHC中是原始的?)并且对我来说还有一步缺失。) - misterbee