如何在Haskell中实现无点的uncurry?

问题描述 投票:2回答:3

我一直在想如何实现不同的标准Haskell函数的无点。目前,我对 uncurry 而我觉得这个问题很不简单。

主要的问题是,我们无法(或者在我看来)对论点进行分组。如果我们有 uncurry (其实。uncurry ($) 就足够了)的使用,解决方案本来是很简单的。

  1. 做一个元组 (f, (x, y)).
  2. 申请 assoc1 :: (a, (b, c)) -> ((a, b), c) 的元组,并得到 ((f, x), y).
  3. 应用未卷曲的 ($) 到该对的第一个元素,并得到 (f x, y).
  4. 应用未卷曲的 ($) 对本身,并得到 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?

haskell tuples currying arrows pointfree
3个回答
4
投票

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).) 是非常可读的


4
投票

毫无艺术性的机械解决方案,由 "向内推送羊脂球".

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

4
投票

有了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

但是这个变体,如上图所示 Jon Purdy言论,

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 一个只是可能是最清晰的,也是最没有噪音的。

© www.soinside.com 2019 - 2024. All rights reserved.