2014-12-06 85 views
6

我偶尔遇到这个问题,最后想问一下是否有一个共同的解决方案或模式。 是否有可能在嵌套上下文引用中创建一个类型变量来自外部上下文的类型?例如,Haskell引用一个类型变量

foo :: a -> ... -> .. 
foo = ... 
    where bar :: a -> ... 

现在bara比富的a不同。通常情况下,这是我想要的,但偶尔它会让生活变得困难,我需要让它们变得一样。我使用肮脏的技巧来迫使类型检查者在过去统一这两种技巧,但偶尔也会受到挫折。这是我最新的例子(一个Parsec函数),它激励我最终提出这个问题。

data Project = ... deriving Enum 
data Stuff = ... 

pProject :: Monad m => P m Stuff 
pProject = do 
    stuff <- pStuff 
    ... 
    convert stuff <$> pEnum :: P m Project 

pEnum :: (Monad m, Enum a) => String -> P m a 
pEnum = ... 

convert函数需要一个类型,因此,我必须指定注释:: P m Project。 但是,这意味着我还必须介绍m,这不幸与功能签名中的m不一样。类型检查报告,这有:

无法推断Monad m1从使用pEnum从上下文Monad m

产生有引用函数签名的m没有一些丑陋的黑客攻击的方法吗?(一个丑陋的黑客是将不会得到执行,但存在只是为了统一这两种类型的伪码。)

回答

13

您正在寻找的ScopedTypeVariables扩展,它可以让你从包含范围引用类型变量。

{-# LANGUAGE ScopedTypeVariables #-} 

为了向下兼容,它仅适用于键入具有明确forall签名。所以,你会写:

pProject :: forall m. Monad m => P m Stuff 

之后,你会能够指向正确类型的变量mpProject范围内。

+5

感谢您指出'ScopedTypeVariables'只适用于具有显式'forall'的签名。难怪它似乎几乎从未工作过...... – Cirdec 2014-12-06 00:51:05

+3

这并不完全正确 - 'ScopedTypeVariables'使类型变量在类声明中作用域,即使没有'forall'也是如此。所以它可以改变一个人为设计的Haskell 2010程序的含义。 – shachaf 2014-12-06 01:52:07