gpt4 book ai didi

haskell - 在 Haskell 中将 `a -> b` 类型的函数转换为 `String -> String` 类型的函数

转载 作者:行者123 更新时间:2023-12-02 13:48:26 27 4
gpt4 key购买 nike

我的意图很简单。我想将 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

我想知道为什么我的代码不起作用以及需要什么样的技巧才能实现我的目标?

谢谢。

最佳答案

你的代码将无法工作,因为 Haskell 不会重用或作用域类型变量; wrap::(Read a, Show b) => (a -> b) -> (String -> String) 中的 a 是完全不同的 a 来自 read s::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 中,为了避免这种情况,您可以打开 the ScopedTypeVariables extension ;有了这个,如果您使用 forall 显式限定所有类型变量,它们的作用域将像值级别名称一样。那么你的代码将变成

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

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

关于haskell - 在 Haskell 中将 `a -> b` 类型的函数转换为 `String -> String` 类型的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18106170/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com