Haskell: Lambda函数 - 错误 - 逃离它们的作用域

3

我定义了以下模块:

module ComplexCompose where

isEven x =
 if x `rem` 2 == 0 then
  (True, "Is Even")
 else
  (False, "Is Odd")


negateIt x = ( not x, "negated")



composer x =
 (c, b ++ ", " ++ d) where (a,b) = isEven x
                           (c,d) = negateIt a

以下对composer的修改有效:
composerV1 x f g =
 (c, b ++ ", " ++ d) where (a,b) = f x
                           (c,d) = g a

我希望让composer函数返回一个将f和g组合起来的lambda函数。我尝试过以下方法:
composerV2 f g =
     \x -> (c, b ++ ", " ++ d) where (a,b) = f x
                                     (c,d) = g a

它不能工作。这个版本有什么问题?

编译器输出:

Couldn't match expected type ‘t0 -> (t5, t4)’
                  with actual type ‘t3’
        because type variables ‘t4’, ‘t5’ would escape their scope
      These (rigid, skolem) type variables are bound by
        the inferred type of
        a :: t5
        b :: t4
        at complex-compose.hs:27:34-44In the expression: f x
      In a pattern binding: (a, b) = f x
      In an equation for ‘c4’:
          c4 f g
            = \ x -> (c, b ++ ", " ++ d)
            where
                (a, b) = f x
                (c, d) = g a
    • Relevant bindings include
        a :: t5 (bound at complex-compose.hs:27:35)
        b :: t4 (bound at complex-compose.hs:27:37)
        f :: t3 (bound at complex-compose.hs:26:4)
        c4 :: t3 -> (t2 -> (t1, [Char])) -> t -> (t1, [Char])
          (bound at complex-compose.hs:26:1)

顺便说一下,以下简单的函数可以使用:

fn f g = \x = g(f x)


我建议先为所有顶层函数添加类型签名。即使这并不能解决问题,但它几乎肯定会使你的类型错误更易于理解。 - Alexis King
你可能会喜欢思考以下定义:foo = (\x -> x+v1, \x -> x++v2) where v1 = 3*x; v2 = "hello, " ++ x。在那个 where 子句中,哪个 x(如果有的话)应该在作用域内?它应该具有什么类型?(为了回答这个问题,即使你将所有数字文字都设为 Integer,我们也不会遇到任何 Haskell 的 Num 层次结构的奇怪情况,因此问题中的有趣信息仍然存在。) - Daniel Wagner
1个回答

0

composerV2 如果我没有在左侧写上 x,它会为我进行类型检查:

composerV2 f g x =
     (c, b ++ ", " ++ d) where (a,b) = f x
                               (c,d) = g a

问题在于,在where子句中,标识符x实际上不在作用域内。错误消息有点令人困惑,但是如果您添加一个类型签名,它就会变得更加精确,这也是一个好习惯。
或者,您可以使用let绑定。
请注意,composerV2 f g = let ... in \x -> ...composerV2 f g x = ...在语义上是相同的,因为您可以部分应用第二个版本。
编辑:使用let绑定的版本如下所示:
composerV2' f g = \x ->
  let (a,b) = f x
      (c,d) = g a
  in (c, b ++ ", " ++ d)

我希望Composer返回一个lambda,它可以组合f和g。这是我的意图。 - coder_bro
就像我之前所说的,这个版本已经实现了这个功能。箭头函数向右关联,因此任何类型为a -> b -> c -> d的函数也可以被解读为a -> (b -> (c -> d))。因此,您可以像这样获取您的函数:let myLambda = composeV2 f g - mbw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接