类型为Read的类,以其名称读取函数是否可行?

时间:2019-07-15 02:04:50

标签: haskell typeclass

假设我具有此功能:

:login
set /p username=Username: 
set /p password=Password: 

// I would put the method of verification right here like an API
if "%username%"=="!api here!" goto :password
echo Wrong username! Try again:
goto :login
:password
if "%password%"=="!api here!" goto :success
echo Wrong password! Try again:
goto :login

:success
cls
echo Success
echo Username: %username%
echo Password: *********
// Injection would take place

,我想从控制台中读取它并应用它。可以做这样的事情吗?:

squared x = x ** 2

1 个答案:

答案 0 :(得分:5)

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

  • 假设您重新定义(+) a b = a - b。现在,read "(+)"是Prelude中的(+)还是您重新定义的(+)运算符?
  • 如果您执行read "foobar",并且尚未将foobar定义为一个函数,那么应该返回什么?然后,如果在模块的其他位置定义了foobar,是否应该突然出现
  • 如果您将import Prelude ()添加到程序顶部,从而从Prelude中删除了所有导入内容,read "preludeFunctionName"应该停止工作吗?

现在,这些问题本身都不是破坏交易的因素-用另一种语言,您仍然可以考虑这些因素来定义read函数。这种情况下的问题是参照透明性:非IO函数应始终在给定相同输入的情况下返回相同输出的属性。由于read的类型是Read a => String -> a,而不是Read a => String -> IO a,因此,鉴于上述函数可以给出一个{不同的答案取决于运行它的确切上下文。 (例如readread "foobar"对同一函数调用会给出不同的答案。)

另一方面,如果您仍然想拥有此功能,则有一种获取它的方法。 hint软件包允许在运行时解释Haskell代码,因此您可以使用此功能来编写类似以下的函数:

let foobar = (+1) in read "foobar"

以上功能可以按如下方式使用:

-- 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

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