看似正确的类型签名拒绝在哪里阻止(Seemingly correct type signature refused in where block)

我一直在讨论Haskell中的延续传递风格。 将Cont monad拆开并删除类型包装器有助于我理解实现。 这是代码:

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad (ap)


newtype Cont r a = Cont {runCont :: (a -> r) -> r}

instance Functor (Cont r) where
  fmap f ka = ka >>= pure . f

instance Applicative (Cont r) where
  (<*>) = ap
  pure = return

instance Monad (Cont r) where

  ka >>= kab = Cont kb'
    where
      -- kb' :: (b -> r) -> r
      kb' hb = ka' ha
        where
          -- ha :: (a -> r)
          ha a = (kab' a) hb

      -- ka' :: (a -> r) -> r
      ka' = runCont ka

      -- kab' :: a -> (b -> r) -> r
      kab' a = runCont (kab a)


  return a = Cont ka'
    where
      -- ka' :: (a -> r) -> r
      ka' ha = ha a
 

这段代码编译(使用GHC 8.0.2),一切似乎都很好。 但是,只要我取消注释where块中的任何(现在注释的)类型签名,我就会收到错误。 例如,如果我取消注释该行

      -- ka' :: (a -> r) -> r
 

我明白了:

    • Couldn't match type ‘a’ with ‘a1’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
        at cont.hs:19:6
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          ka' :: forall a1. (a1 -> r) -> r
        at cont.hs:27:14
      Expected type: (a1 -> r) -> r
        Actual type: (a -> r) -> r
    • In the expression: runCont ka
      In an equation for ‘ka'’: ka' = runCont ka
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: (a -> r) -> r
                ka' = runCont ka
                kab' a = runCont (kab a)
    • Relevant bindings include
        ka' :: (a1 -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

所以我尝试使用类型通配符让编译器告诉我应该放在哪个类型的签名。 因此,我尝试了以下签名:

      ka' :: _
 

这给出了以下错误:

    • Found type wildcard ‘_’ standing for ‘(a -> r) -> r’
      Where: ‘r’ is a rigid type variable bound by
               the instance declaration at cont.hs:15:10
             ‘a’ is a rigid type variable bound by
               the type signature for:
                 (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
               at cont.hs:19:6
      To use the inferred type, enable PartialTypeSignatures
    • In the type signature:
        ka' :: _
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: _
                ka' = runCont ka
                kab' a = runCont (kab a)
      In the instance declaration for ‘Monad (Cont r)’
    • Relevant bindings include
        ka' :: (a -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

现在我真的很困惑,编译器告诉我ka'的类型是(a -> r) -> r但是当我尝试用这种类型明确地注释ka'时,编译失败了。 首先我认为我缺少ScopedTypeVariables但它似乎没有什么区别。

这里发生了什么?

编辑这类似于“ 为什么这个函数在where子句中使用范围类型变量而不是typecheck? ”的问题,因为它需要一个显式的forall来绑定类型变量。 但是它不是重复的,因为这个问题的答案也需要InstanceSigs扩展。

I have been messing around with continuation passing style in Haskell. Taking the Cont monad apart and removing the type wrappers helped me in understanding the implementation. Here is the code:

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad (ap)


newtype Cont r a = Cont {runCont :: (a -> r) -> r}

instance Functor (Cont r) where
  fmap f ka = ka >>= pure . f

instance Applicative (Cont r) where
  (<*>) = ap
  pure = return

instance Monad (Cont r) where

  ka >>= kab = Cont kb'
    where
      -- kb' :: (b -> r) -> r
      kb' hb = ka' ha
        where
          -- ha :: (a -> r)
          ha a = (kab' a) hb

      -- ka' :: (a -> r) -> r
      ka' = runCont ka

      -- kab' :: a -> (b -> r) -> r
      kab' a = runCont (kab a)


  return a = Cont ka'
    where
      -- ka' :: (a -> r) -> r
      ka' ha = ha a
 

This code compiles (using GHC 8.0.2) and everything seems fine. However, as soon as I uncomment any of the (now commented) type signatures in the where block I get an error. For exapmle, if I uncomment the line

      -- ka' :: (a -> r) -> r
 

I get:

    • Couldn't match type ‘a’ with ‘a1’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
        at cont.hs:19:6
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          ka' :: forall a1. (a1 -> r) -> r
        at cont.hs:27:14
      Expected type: (a1 -> r) -> r
        Actual type: (a -> r) -> r
    • In the expression: runCont ka
      In an equation for ‘ka'’: ka' = runCont ka
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: (a -> r) -> r
                ka' = runCont ka
                kab' a = runCont (kab a)
    • Relevant bindings include
        ka' :: (a1 -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

So I tried using a type wildcard to let the compiler tell me what type signature I should put there. As such I tried the following signature:

      ka' :: _
 

Which gave the following error:

    • Found type wildcard ‘_’ standing for ‘(a -> r) -> r’
      Where: ‘r’ is a rigid type variable bound by
               the instance declaration at cont.hs:15:10
             ‘a’ is a rigid type variable bound by
               the type signature for:
                 (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
               at cont.hs:19:6
      To use the inferred type, enable PartialTypeSignatures
    • In the type signature:
        ka' :: _
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: _
                ka' = runCont ka
                kab' a = runCont (kab a)
      In the instance declaration for ‘Monad (Cont r)’
    • Relevant bindings include
        ka' :: (a -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

Now I am really confused, the compiler tells me the type of ka' is (a -> r) -> r but as soon as I try to explicitely annotate ka' with this type, compiling fails. First I thought I was missing ScopedTypeVariables but it does not seem to make a difference.

What is going on here?

EDIT This is similar to the question " Why does this function that uses a scoped type variable in a where clause not typecheck? " in that it requires an explicit forall to bind type variables. However it is not a duplicate since the answer to this question also requires the InstanceSigs extension.

最满意答案

说得通。 毕竟,那些s和b来自哪里? 我们无法知道它们与(>>=)的多态性相关并return 。 但是,很容易修复,如评论中所述:give (>>=)和return类型签名,提及a和b ,抛出必要的语言扩展,并且嘿presto:

{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE InstanceSigs #-} import Control.Monad (ap) newtype Cont r a = Cont {runCont :: (a -> r) -> r} instance Functor (Cont r) where fmap f ka = ka >>= pure . f instance Applicative (Cont r) where (<*>) = ap pure = return instance Monad (Cont r) where (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b ka >>= kab = Cont kb' where kb' :: (b -> r) -> r kb' hb = ka' ha where ha :: (a -> r) ha a = (kab' a) hb ka' :: (a -> r) -> r ka' = runCont ka kab' :: a -> (b -> r) -> r kab' a = runCont (kab a) return :: forall a. a -> Cont r a return a = Cont ka' where ka' :: (a -> r) -> r ka' ha = ha a

我觉得在所有这些事情中都有一个龙珠笑话,但这个笑话me惊讶。

Makes sense. After all, where did those as and bs come from? We have no way to know they're connected to the polymorphism of (>>=) and return. It's easy to fix, though, as mentioned in the comments: give (>>=) and return type signatures that mention a and b, toss in the requisite language extension, and hey presto:

{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE InstanceSigs #-} import Control.Monad (ap) newtype Cont r a = Cont {runCont :: (a -> r) -> r} instance Functor (Cont r) where fmap f ka = ka >>= pure . f instance Applicative (Cont r) where (<*>) = ap pure = return instance Monad (Cont r) where (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b ka >>= kab = Cont kb' where kb' :: (b -> r) -> r kb' hb = ka' ha where ha :: (a -> r) ha a = (kab' a) hb ka' :: (a -> r) -> r ka' = runCont ka kab' :: a -> (b -> r) -> r kab' a = runCont (kab a) return :: forall a. a -> Cont r a return a = Cont ka' where ka' :: (a -> r) -> r ka' ha = ha a

I feel like there's a Dragonball joke in all these kas and has, but the joke escapes me.

看似正确的类型签名拒绝在哪里阻止(Seemingly correct type signature refused in where block)

我一直在讨论Haskell中的延续传递风格。 将Cont monad拆开并删除类型包装器有助于我理解实现。 这是代码:

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad (ap)


newtype Cont r a = Cont {runCont :: (a -> r) -> r}

instance Functor (Cont r) where
  fmap f ka = ka >>= pure . f

instance Applicative (Cont r) where
  (<*>) = ap
  pure = return

instance Monad (Cont r) where

  ka >>= kab = Cont kb'
    where
      -- kb' :: (b -> r) -> r
      kb' hb = ka' ha
        where
          -- ha :: (a -> r)
          ha a = (kab' a) hb

      -- ka' :: (a -> r) -> r
      ka' = runCont ka

      -- kab' :: a -> (b -> r) -> r
      kab' a = runCont (kab a)


  return a = Cont ka'
    where
      -- ka' :: (a -> r) -> r
      ka' ha = ha a
 

这段代码编译(使用GHC 8.0.2),一切似乎都很好。 但是,只要我取消注释where块中的任何(现在注释的)类型签名,我就会收到错误。 例如,如果我取消注释该行

      -- ka' :: (a -> r) -> r
 

我明白了:

    • Couldn't match type ‘a’ with ‘a1’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
        at cont.hs:19:6
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          ka' :: forall a1. (a1 -> r) -> r
        at cont.hs:27:14
      Expected type: (a1 -> r) -> r
        Actual type: (a -> r) -> r
    • In the expression: runCont ka
      In an equation for ‘ka'’: ka' = runCont ka
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: (a -> r) -> r
                ka' = runCont ka
                kab' a = runCont (kab a)
    • Relevant bindings include
        ka' :: (a1 -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

所以我尝试使用类型通配符让编译器告诉我应该放在哪个类型的签名。 因此,我尝试了以下签名:

      ka' :: _
 

这给出了以下错误:

    • Found type wildcard ‘_’ standing for ‘(a -> r) -> r’
      Where: ‘r’ is a rigid type variable bound by
               the instance declaration at cont.hs:15:10
             ‘a’ is a rigid type variable bound by
               the type signature for:
                 (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
               at cont.hs:19:6
      To use the inferred type, enable PartialTypeSignatures
    • In the type signature:
        ka' :: _
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: _
                ka' = runCont ka
                kab' a = runCont (kab a)
      In the instance declaration for ‘Monad (Cont r)’
    • Relevant bindings include
        ka' :: (a -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

现在我真的很困惑,编译器告诉我ka'的类型是(a -> r) -> r但是当我尝试用这种类型明确地注释ka'时,编译失败了。 首先我认为我缺少ScopedTypeVariables但它似乎没有什么区别。

这里发生了什么?

编辑这类似于“ 为什么这个函数在where子句中使用范围类型变量而不是typecheck? ”的问题,因为它需要一个显式的forall来绑定类型变量。 但是它不是重复的,因为这个问题的答案也需要InstanceSigs扩展。

I have been messing around with continuation passing style in Haskell. Taking the Cont monad apart and removing the type wrappers helped me in understanding the implementation. Here is the code:

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad (ap)


newtype Cont r a = Cont {runCont :: (a -> r) -> r}

instance Functor (Cont r) where
  fmap f ka = ka >>= pure . f

instance Applicative (Cont r) where
  (<*>) = ap
  pure = return

instance Monad (Cont r) where

  ka >>= kab = Cont kb'
    where
      -- kb' :: (b -> r) -> r
      kb' hb = ka' ha
        where
          -- ha :: (a -> r)
          ha a = (kab' a) hb

      -- ka' :: (a -> r) -> r
      ka' = runCont ka

      -- kab' :: a -> (b -> r) -> r
      kab' a = runCont (kab a)


  return a = Cont ka'
    where
      -- ka' :: (a -> r) -> r
      ka' ha = ha a
 

This code compiles (using GHC 8.0.2) and everything seems fine. However, as soon as I uncomment any of the (now commented) type signatures in the where block I get an error. For exapmle, if I uncomment the line

      -- ka' :: (a -> r) -> r
 

I get:

    • Couldn't match type ‘a’ with ‘a1’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
        at cont.hs:19:6
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          ka' :: forall a1. (a1 -> r) -> r
        at cont.hs:27:14
      Expected type: (a1 -> r) -> r
        Actual type: (a -> r) -> r
    • In the expression: runCont ka
      In an equation for ‘ka'’: ka' = runCont ka
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: (a -> r) -> r
                ka' = runCont ka
                kab' a = runCont (kab a)
    • Relevant bindings include
        ka' :: (a1 -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

So I tried using a type wildcard to let the compiler tell me what type signature I should put there. As such I tried the following signature:

      ka' :: _
 

Which gave the following error:

    • Found type wildcard ‘_’ standing for ‘(a -> r) -> r’
      Where: ‘r’ is a rigid type variable bound by
               the instance declaration at cont.hs:15:10
             ‘a’ is a rigid type variable bound by
               the type signature for:
                 (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b
               at cont.hs:19:6
      To use the inferred type, enable PartialTypeSignatures
    • In the type signature:
        ka' :: _
      In an equation for ‘>>=’:
          ka >>= kab
            = Cont kb'
            where
                kb' hb
                  = ka' ha
                  where
                      ha a = (kab' a) hb
                ka' :: _
                ka' = runCont ka
                kab' a = runCont (kab a)
      In the instance declaration for ‘Monad (Cont r)’
    • Relevant bindings include
        ka' :: (a -> r) -> r (bound at cont.hs:28:7)
        kab' :: a -> (b -> r) -> r (bound at cont.hs:31:7)
        kab :: a -> Cont r b (bound at cont.hs:19:10)
        ka :: Cont r a (bound at cont.hs:19:3)
        (>>=) :: Cont r a -> (a -> Cont r b) -> Cont r b
          (bound at cont.hs:19:3)
Failed, modules loaded: none.
 

Now I am really confused, the compiler tells me the type of ka' is (a -> r) -> r but as soon as I try to explicitely annotate ka' with this type, compiling fails. First I thought I was missing ScopedTypeVariables but it does not seem to make a difference.

What is going on here?

EDIT This is similar to the question " Why does this function that uses a scoped type variable in a where clause not typecheck? " in that it requires an explicit forall to bind type variables. However it is not a duplicate since the answer to this question also requires the InstanceSigs extension.

最满意答案

说得通。 毕竟,那些s和b来自哪里? 我们无法知道它们与(>>=)的多态性相关并return 。 但是,很容易修复,如评论中所述:give (>>=)和return类型签名,提及a和b ,抛出必要的语言扩展,并且嘿presto:

{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE InstanceSigs #-} import Control.Monad (ap) newtype Cont r a = Cont {runCont :: (a -> r) -> r} instance Functor (Cont r) where fmap f ka = ka >>= pure . f instance Applicative (Cont r) where (<*>) = ap pure = return instance Monad (Cont r) where (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b ka >>= kab = Cont kb' where kb' :: (b -> r) -> r kb' hb = ka' ha where ha :: (a -> r) ha a = (kab' a) hb ka' :: (a -> r) -> r ka' = runCont ka kab' :: a -> (b -> r) -> r kab' a = runCont (kab a) return :: forall a. a -> Cont r a return a = Cont ka' where ka' :: (a -> r) -> r ka' ha = ha a

我觉得在所有这些事情中都有一个龙珠笑话,但这个笑话me惊讶。

Makes sense. After all, where did those as and bs come from? We have no way to know they're connected to the polymorphism of (>>=) and return. It's easy to fix, though, as mentioned in the comments: give (>>=) and return type signatures that mention a and b, toss in the requisite language extension, and hey presto:

{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE InstanceSigs #-} import Control.Monad (ap) newtype Cont r a = Cont {runCont :: (a -> r) -> r} instance Functor (Cont r) where fmap f ka = ka >>= pure . f instance Applicative (Cont r) where (<*>) = ap pure = return instance Monad (Cont r) where (>>=) :: forall a b. Cont r a -> (a -> Cont r b) -> Cont r b ka >>= kab = Cont kb' where kb' :: (b -> r) -> r kb' hb = ka' ha where ha :: (a -> r) ha a = (kab' a) hb ka' :: (a -> r) -> r ka' = runCont ka kab' :: a -> (b -> r) -> r kab' a = runCont (kab a) return :: forall a. a -> Cont r a return a = Cont ka' where ka' :: (a -> r) -> r ka' ha = ha a

I feel like there's a Dragonball joke in all these kas and has, but the joke escapes me.