使用字符串的内容来调用具有相同名称的函数

时间:2014-01-14 19:09:51

标签: haskell eval

我有一个类似以下的主要内容:

main :: IO ()
main = do
  args <- getArgs
  putStrLn $ functionName args
  where 
    functionName args = "problem" ++ (filter (/= '"') $ show (args!!0))

我没有像现在这样把名称放到标准输出中,而是想调用函数。

我知道这个事实,我可以使用提示(如Haskell: how to evaluate a String like "1+2"中提到的那样),但我认为仅仅获得这个简单的函数名称会有点过分。

在当前阶段,如果该功能不存在,程序是否会崩溃无关紧要!

3 个答案:

答案 0 :(得分:6)

如果不采取特殊措施来保护它们,函数的名称可能会在编译的Haskell程序中完全消失。

我建议你制作一张大型顶级地图:

import Data.Map ( Map )
import qualified Data.Map as Map

functions :: Map String (IO ())
functions = Map.fromList [("problem1", problem1), ...]

call :: String -> IO ()
call name =
    case Map.lookup name of
        Nothing -> fail $ name + " not found"
        Just m -> m

main :: IO ()
main = do
  args <- getArgs
  call $ functionName args
  where 
    functionName args = "problem" ++ (filter (/= '"') $ show (args!!0))

答案 1 :(得分:6)

如果你要这样做,你有几种方法,但到目前为止最简单的方法就是模式匹配

此方法要求您要调用的所有函数都具有相同的类型签名:

problem1 :: Int
problem1 = 1

problem2 :: Int
problem2 = 2

runFunc :: String -> Maybe Int
runFunc "problem1" = Just problem1
runFunc "problem2" = Just problem2
runFunc _ = Nothing

main = do
    args <- getArgs
    putStrLn $ runFunc $ functionName args

这需要您在每次添加新runFunc时向problemN添加一行,但这非常易于管理。

答案 2 :(得分:2)

您无法获得标识符的字符串表示形式,而不是没有花哨的非标准功能,因为编译后不会保留该信息。因此,您将不得不将这些函数名称写为字符串常量某处

如果函数定义无论如何都在一个文件中,我建议使用数据类型和lambda来避免完全复制这些函数名称:

Data Problem = {
    problemName :: String,
    evalProblem :: IO () # Or whatever your problem function signatures are
    }

problems = [Problem]
problems = [
    Problem {
        problemName = "problem1",
        evalProblem = do ... # Insert code here
        },
    Problem
        problemName = "problem2",
        evalProblem = do ... # Insert code here
        }
    ]

main :: IO ()
main = do
    args <- getArgs
    case find (\x -> problemName x == (args!!0)) problems of
        Just x -> evalProblem x
        Nothing -> # Handle error

修改:为了澄清,我要说的是,你有一个XY Problem的重要内容。