您的代码将无法工作,因为 Haskell 不会重用或作用域类型变量;a
in与inwrap :: (Read a, Show b) => (a -> b) -> (String -> String)
完全不同a
(read s :: a
它们都是普遍量化的)。这是a1
错误消息中的来源;GHC 正在将程序转换为
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a1)
但是,f
的参数类型在内部是固定的wrap
,因此只需删除类型注释即可。你的功能变成
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s)
-- Or wrap f = show . f . read
你可以使用它:
ghci> map ($ "42") [wrap (+ (7 :: Integer)), wrap (* (2.0 :: Double))]
["49","84.0"]
请注意,这意味着read s
您不能写下它的类型。在 Haskell 2010(或 98)中,解决此问题的唯一方法是使用类似asTypeOf :: a -> a -> a
; asTypeOf
is just const
,但由于它的类型签名,它将第一个返回的参数限制为与第二个相同的类型。然后,当然,你必须想出一个 type 的变量a
。以下将为此工作:
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s `asTypeOf` fInput)
where fInput = undefined
fOutput = f fInput -- I still can't give this a type signature
在 GHC 中,为避免这种ScopedTypeVariables
情况,您可以打开扩展;有了它,如果你用 a 明确地限定所有类型变量,它们的forall
作用域就像值级名称一样。然后你的代码会变成
{-# LANGUAGE ScopedTypeVariables #-}
wrap :: forall a b. (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a)
但是请记住,对于这个简单的示例,您根本不需要任何类型注释。