我一直在想如何实现不同的标准Haskell函数的无点。目前,我对 uncurry
而我觉得这个问题很不简单。
主要的问题是,我们无法(或者在我看来)对论点进行分组。如果我们有 uncurry
(其实。uncurry ($)
就足够了)的使用,解决方案本来是很简单的。
(f, (x, y))
.assoc1 :: (a, (b, c)) -> ((a, b), c)
的元组,并得到 ((f, x), y)
.($)
到该对的第一个元素,并得到 (f x, y)
.($)
对本身,并得到 f x y
.如果没有不干不净的... ($)
我们将不得不分别提取这对元素的两个元素。例如:。
uncurry f pair = f (fst pair) (snd pair)
我不认为这是个顺利实现无点的方法。
事实上,我们已经得到了这个无卷曲的 ($)
应我们的要求。Control.Arrow.apply
(其他有用的解决组合器也可以从我们的要求中导入) Control.Arrow
). 因此,。
import Control.Arrow ((>>>), (&&&), first, app)
myUncurry = let myAssoc1 = (fst &&& (fst . snd)) &&& (snd . snd)
in (,) >>> (>>> myAssoc1 >>> first app >>> app)
然而,这感觉有点像作弊。
有没有其他的方法来解决这个问题,而不需要任何类似的东西。app
?
join
在函数上给你 (a -> a -> b) -> a -> b
,所以。
myUncurry f = join (\x y -> f (fst x) (snd y))
myUncurry f = join (\x -> f (fst x) . snd)
myUncurry f = join ((.snd) . f . fst)
myUncurry f = join ((.fst) ((.snd) . f))
myUncurry f = join ((.fst) ((.) (.snd) f))
myUncurry = join . (.fst) . \f -> (.) (.snd) f
myUncurry = join . (.fst) . ((.snd).)
join . (.fst) . ((.snd).)
是非常可读的
毫无艺术性的机械解决方案,由 "向内推送羊脂球".
uncurry f (x,y) = f x y
uncurry f p = f (fst p) (snd p)
uncurry f = \p -> f (fst p) (snd p)
uncurry f = (<*>) (\p -> f (fst p)) (\p -> snd p)
uncurry f = (<*>) (f . fst) snd
uncurry = \f -> (<*>) (f . fst) snd
uncurry = flip (\f -> (<*>) (f . fst)) snd
uncurry = flip ((<*>) . (\f -> f . fst)) snd
uncurry = flip ((<*>) . (. fst)) snd
有了Lambda Calculus' S 组合器。 Sabc = (a <*> b) c = a c $ b c
,
uncurry f (x,y) = f (fst (x,y)) (snd (x,y))
= (f . fst <*> snd) (x,y)
uncurry f = (<*> snd) (f . fst)
= (<*> snd) . (. fst) $ f
因此,
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry = (<*> snd) . (. fst)
(编辑。)
不过如上图所示,在那里留了一个明确的论点,还是更有可读性的(也有点阐明性)。
uncurry f = f . fst <*> snd
uncurry f = liftA2 f fst snd
只是可能是最清晰的。
这是因为对于函数来说,单项式和应用式在权力上是等价的。
(k =<< f) x = k (f x) x = flip k x (f x) = (flip k <*> f) x
-- i.e., uncurry f = flip (f . fst) =<< snd
和 liftA2 f fst snd
根据定义,意味着:
= [ f a b | a <- fst ; b <- snd ]
=
do { a <- fst ;
b <- snd ;
return (f a b)
}
= \x -> let
{ a = fst x ;
b = snd x ;
}
in const (f a b) x
(第一个用单体理解法写的)。因此。
uncurry f x = liftA2 f fst snd x
= let
{ a = fst x ;
b = snd x ;
}
in f a b
=
f (fst x) (snd x)
=
(f . fst <*> snd) x
=
(flip (f . fst) =<< snd) x
=
flip (f . fst) (snd x) x
=
(flip (f . fst) . snd) x x
=
join (flip (f . fst) . snd) x
=
join (flip (f . fst) <$> snd) x
继而 等效性, k =<< m = join (fmap k m)
(而对于函数。(<$>) = fmap = (.)
).
所以我们在这里又找到了另一种表达方式。
uncurry f x = join (flip (f . fst) . snd)
= liftA2 f fst snd
= f . fst <*> snd
= flip (f . fst) =<< snd
该 liftA2
一个只是可能是最清晰的,也是最没有噪音的。