Ale*_*x R 3 polymorphism haskell let monomorphism
我有一些代码使用类型消除实例的歧义(真正的代码使用GHC.TypeLits单例作为类型标签,但我不认为这是密切相关的)我想使用let绑定来避免文本级重复; 不幸的是,这使结果单形化.
以下是该问题的一个示例:
class Foo a where
foo :: a
instance Foo Int where
foo = 0
instance Foo Char where
foo = 'a'
data Bar a = Bar String
deriving (Show)
bar :: forall a. (Show a, Foo a) => a -> Bar a
bar _ = Bar $ show (foo :: a)
idInt :: Bar Int -> Bar Int
idInt = id
idChar :: Bar Char -> Bar Char
idChar = id
main = let quux = bar undefined in
print (idInt quux) >> print (idChar quux)
Run Code Online (Sandbox Code Playgroud)
上面的代码不编译(但是,当然,如果我输入注释quux是多态的,一切工作正常),正确地抱怨说,它无法比拟Int用Char.有没有什么方法可以让编译成功而没有类型注释而不重复bar undefined每个使用网站?
{-# LANGUAGE NoMonomorphismRestriction #-}
Run Code Online (Sandbox Code Playgroud)
或者,如果你想要一些不那么全球化
let quux () = bar undefined in
print (idInt (quux ()) >> print (idChar (quux ()))
Run Code Online (Sandbox Code Playgroud)
后者工作的原因是绑定只有在等号左边没有参数时才是单态的.
let foo = \x y -> x + y -- :: Integer -> Integer -> Integer
let bar x y = x + y -- :: (Num a) => a -> a -> a
Run Code Online (Sandbox Code Playgroud)
因此,quux为了不进行单形化,你必须在等号的左边给它一个参数.如果quux不是值而是函数,您可以简单地扩展以获得相同的效果:
let quux x = bar undefined x in ...
Run Code Online (Sandbox Code Playgroud)
对于前者,不要担心性能 - 如果你总是把它称为quux (),那么它将被内联并生成与具有显式类型签名的版本相同的代码.