2017-08-08 39 views
0

所以我想用关联列表(或地图)构建一个函数表。我做了一些简单的测试,发现以下内容:完全执行curried的函数可以正常工作,但部分curried函数不能存储在关联列表中。下面是正常工作的代码:关联列表中的部分咖喱函数(地图)

import Data.List 
import System.IO 

func1 :: IO() 
func1 = putStrLn "1" 

func2 :: IO() 
func2 = putStrLn "2" 

funcTable = [ (1, func1) 
      , (2, func2)] 

callFunc :: Int -> IO() 
callFunc i = do 
    let justFunc = lookup i funcTable 
    case justFunc of 
    Just func -> func 
    Nothing -> putStrLn "Wrong!" 

main = do 
    callFunc 1 
    callFunc 2 
    callFunc 3 

但是,下面的代码不会编译:

import Data.List 
import System.IO 

func1 :: IO() 
func1 = putStrLn "1" 

func2 :: String -> IO() 
func2 s = putStrLn s 

funcTable = [ (1, func1) 
      , (2, func2)] 

callFunc :: Int -> IO() 
callFunc i = do 
    let justFunc = lookup i funcTable 
    case justFunc of 
    Just func1 -> func1 
    Just func2 -> func2 "OK" 
    Nothing -> putStrLn "Wrong!" 

main = do 
    callFunc 1 
    callFunc 2 
    callFunc 3 

我在不编译代码所做的唯一的变化是我改变FUNC2到部分咖喱功能。任何诡计,使其工作?

+4

问题不在于“部分curried”函数不能存储在“关联”列表中。问题是这两个函数没有相同的类型。此外,在'case'中,'Just func1'不会检查函数是否确实是'func1',在这种情况下'func1'是一个*局部变量*。 –

+0

如果您的'callFunc'函数无论如何都必须知道所有函数,那么保留字典有什么意义? –

+1

尝试写入'funcTable'的类型。你会发现它是生病的输入。 – chi

回答

2

您的问题与将值应用于函数无关。问题是两个值都有不同的类型。什么是[(1,func1),(2,func2)]的类型? [(Int,IO())][(Int, String -> IO())]?两者都是错误的。

最简单的解决方案是将不同类型的值包装成新的。

data Action 
    = SimpleAction (IO()) 
    | StringAction (String -> IO()) 

table :: [(Int, Action)] 
table = [(1, SimpleAction func1), (2, StringAction func2)] 

callFunc :: Int -> IO() 
callFunc i = case lookup i table of 
    Just (SimpleAction action) -> action 
    Just (StringAction action) -> action "OK" 
    Nothing -> error "wrong" 

请注意,func1不是一个函数的方式。