我的意图很简单。我希望将a -> b类型的函数包装到String -> 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我想知道为什么我的代码不能工作,需要什么样的黑客才能实现我的目标?
谢谢。
发布于 2013-08-07 14:53:57
您的代码无法工作,因为Haskell不重用或范围类型变量;wrap :: (Read a, Show b) => (a -> b) -> (String -> String)中的a与read s :: a中的a完全不同(而且它们都是通用量化的)。这是错误消息中a1的源;GHC是alpha-将程序转换为
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只是const,但是由于它的类型签名,它将第一个返回的参数限制为与其第二个相同的类型。当然,您必须生成一个类型为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中,为了避免这种情况,您可以打开 extension;在打开它时,如果显式地用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-07 14:48:48
要显式地指定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 . readhttps://stackoverflow.com/questions/18106170
复制相似问题