7

我的意图很简单。我想将类型的函数包装a -> bString -> String(以便可以将一堆异构函数放入列表中)。所以我写:

wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a)

但是,ghc投诉:

Could not deduce (Read a1) arising from a use of `read'
from the context (Read a, Show b)
  bound by the type signature for
             wrap :: (Read a, Show b) => (a -> b) -> String -> String

我想知道为什么我的一段代码不起作用以及需要什么样的黑客来实现我的目标?

谢谢。

4

2 回答 2

13

您的代码将无法工作,因为 Haskell 不会重用或作用域类型变量;ain与inwrap :: (Read a, Show b) => (a -> b) -> (String -> String)完全不同aread 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; asTypeOfis 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)

但是请记住,对于这个简单的示例,您根本不需要任何类型注释。

于 2013-08-07T14:53:57.693 回答
10

要明确指定类型read s,您需要类似ScopedTypeVariables

{-# LANGUAGE ScopedTypeVariables #-}
...
wrap :: forall a b. (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a)

因为否则:: a函数内部的注释引用了a与类型签名中的不同的类型(它隐含的意思是:: forall a. a)。但请注意,您也可以完全删除类型注释:

wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s)

由于read s可以推断出类型。这也可以让你简化身体

wrap f = show . f . read
于 2013-08-07T14:48:48.870 回答