代码之家  ›  专栏  ›  技术社区  ›  Jonas

关于哈斯克尔的货币化和无点风格的困惑

  •  9
  • Jonas  · 技术社区  · 15 年前

    我试图实现这个功能

    every :: (a -> IO Bool) -> [a] -> IO Bool 
    

    哪个是主题 this question . 我试过这么做 没有显式递归 . 我想出了以下代码

    every f xs = liftM (all id) $ sequence $ map f xs
    

    我的函数不起作用,因为它不是懒惰的(这在问题中是必需的),所以这里没有upvotes:-。

    然而,我并没有就此止步。我试着做这个功能 无点 这样它就会变短(甚至更冷)。因为争论 f xs 是我刚才删除的表达式中的最后一个:

    every = liftM (all id) $ sequence $ map 
    

    但这并没有像预期的那样奏效,事实上根本没有奏效:

        [1 of 1] Compiling Main             ( stk.hs, interpreted )
    
        stk.hs:53:42:
            Couldn't match expected type `[m a]'
                   against inferred type `(a1 -> b) -> [a1] -> [b]'
            In the second argument of `($)', namely `map'
            In the second argument of `($)', namely `sequence $ map'
            In the expression: liftM (all id) $ sequence $ map
        Failed, modules loaded: none.
    

    为什么会这样?我的印象是可以简单地删除后面的函数参数,这基本上就是curring的目的。

    1 回复  |  直到 15 年前
        1
  •  25
  •   Dave    15 年前

    美元的定义是

    f $ x = f x
    

    让我们用括号将函数括起来:

    every f xs = (liftM (all id)) (sequence ((map f) xs))
    

    你的课程版本:

    every = (liftM (all id)) (sequence map)
    

    正如你所注意到的,这些是不相同的。只能在最后应用尾随函数参数时删除它们。例如,

    f x = g c x
    

    实际上是

    f x = (g c) x
    

    (g c)对x的应用排在最后,所以你可以写

    f = g c
    

    应用程序运算符$的一个模式是它经常成为复合运算符。在无点版本中。这是因为

    f $ g $ x
    

    等于

    (f . g) $ x
    

    例如,

    every f xs = liftM (all id) $ sequence $ map f xs
    

    可以成为

    every f xs = (liftM (all id) . sequence . map f) xs
    

    此时可以删除xs:

    every f = liftM (all id) . sequence . map f
    

    消除参数f更困难,因为它是在复合运算符之前应用的。我们用点的定义 http://www.haskell.org/haskellwiki/Pointfree :

    dot = ((.) . (.))
    

    有了积分,这是

    (f `dot` g) x = f . g x
    

    这正是我们要让每一个积分都是免费的:

    every = (liftM (all id) . sequence) `dot` map
    

    遗憾的是,由于haskell类型系统中的限制,这个系统需要显式的类型签名:

    every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool