首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell中“a -> b”型函数转化为“`String -> `String”型函数

Haskell中“a -> b”型函数转化为“`String -> `String”型函数
EN

Stack Overflow用户
提问于 2013-08-07 14:31:25
回答 2查看 340关注 0票数 7

我的意图很简单。我希望将a -> b类型的函数包装到String -> String中(这样就可以将一组异构函数放入列表中)。所以我写:

代码语言:javascript
复制
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a)

然而,ghc的投诉:

代码语言:javascript
复制
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

我想知道为什么我的代码不能工作,需要什么样的黑客才能实现我的目标?

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-07 14:53:57

您的代码无法工作,因为Haskell不重用或范围类型变量;wrap :: (Read a, Show b) => (a -> b) -> (String -> String)中的aread s :: a中的a完全不同(而且它们都是通用量化的)。这是错误消息中a1的源;GHC是alpha-将程序转换为

代码语言:javascript
复制
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a1)

但是,f的参数类型是固定在wrap内部的,因此只需删除类型注释就可以了。

代码语言:javascript
复制
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s)
  -- Or wrap f = show . f . read

你可以用它:

代码语言:javascript
复制
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的变量。为此,将采取以下措施:

代码语言:javascript
复制
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限定所有类型变量,它们的作用域就像值级名称一样。那么你的代码就会变成

代码语言:javascript
复制
{-# LANGUAGE ScopedTypeVariables #-}
wrap :: forall a b. (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s :: a)

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

票数 13
EN

Stack Overflow用户

发布于 2013-08-07 14:48:48

要显式地指定read s的类型,您需要类似于ScopedTypeVariables的东西

代码语言:javascript
复制
{-# 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)。但是请注意,您也可以完全删除类型注释:

代码语言:javascript
复制
wrap :: (Read a, Show b) => (a -> b) -> (String -> String)
wrap f = \s -> show $ f (read s)

因为可以推断read s的类型。这也让你把身体简化为

代码语言:javascript
复制
wrap f = show . f . read
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18106170

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档