输入 class Read,是否可以通过名称读取函数?

Type class Read, is it posibble to read a function by it name?

假设我有这个功能:

squared x = x ** 2

我想从控制台读取它,然后应用它。可以这样做吗?:

gchi> (read("squared) :: Int -> Int) 4

否;一般来说,这是不可能的。要了解原因,请考虑如果存在此功能可能会发生的几种情况:

  • 假设您重新定义 (+) a b = a - b。现在,read "(+)" 应该是 Prelude 中的 (+),还是您重新定义的 (+) 运算符?
  • 如果做read "foobar",而foobar还没有被定义为函数,那么这个return应该怎么办?那么如果 foobar 在模块的其他地方定义,这个 return 值是否应该突然改变?
  • 如果您将 import Prelude () 添加到程序的顶部,这会删除 Prelude 中的所有导入,read "preludeFunctionName" 是否应该停止工作?

现在,none 这些问题本身就是破坏者 — 在另一种语言中,您仍然可以定义一个 read 函数来考虑这些问题。这种情况下的问题是参照透明度:属性非IO函数应该总是return给定相同输入的相同输出(秒)。因为 read 的类型是 Read a => String -> a,而不是 Read a => String -> IO a,你不能像你想要的那样创建 read 的实例,因为上面的函数可以给出一个不同的答案取决于它所在的确切上下文 运行。 (例如 read "foobar"let foobar = (+1) in read "foobar" 会对同一个函数调用给出不同的答案。)

另一方面,如果您仍想拥有此功能,可以通过一种方法获得。 hint 包允许 Haskell 代码在 运行 时被解释,因此您可以使用此功能编写如下函数:

-- Warning: the following code is untested
-- Please comment if you find any errors!
import Language.Haskell.Interpreter

readFn :: Typeable a
       => [ModuleName]   -- ^ Modules to search
       -> String         -- ^ Function to read
       -> a              -- ^ Witness for the type a
       -> IO (Either InterpreterError a)
readFn m f w = runInterpreter $ do
    setImports m
    interpret f w

以上函数可以如下使用:

readFn ["Prelude"] "(+)" (as :: Num a => a -> a -> a)

其中 as 来自 Language.Haskell.Interpreter.