Haskell查找表返回函数

时间:2014-10-02 02:29:16

标签: haskell

试图扩展" The Maybe monad" this页面上的示例。他们的查询表phonebook

phonebook :: [(String, String)]
phonebook = [ ("Bob",   "01788 665242"),
              ("Fred",  "01624 556442"),
              ("Alice", "01889 985333"),
              ("Jane",  "01732 187565") ]

并且链接了monad例子:

getRegistrationNumber :: String       -- their name
                      -> Maybe String -- their registration number
getRegistrationNumber name = 
  lookup name phonebook >>= 
    (\number -> lookup number governmentalDatabase)

如果我们想要返回一个函数(然后返回一个特定类型)会发生什么?因此,从他们的示例扩展而不是查找注册号,我们希望查找查询年龄,他们的ZIP或支付财产税的年份。鉴于这些示例,INT似乎适用于前两个,而List of Ints适用于前两个。 第一个问题:由于查找表有一个类型,函数的所有返回类型是否必须属于同一类型?我假设是,但我不确定,因此下一个问题。

让我们说这些'发现'返回相同类型[Int]的函数。也许是这样的:

getAge :: String -> Maybe [Int]
getAge phoneNumberString =
   lookup name phonebook >>==
      (\phoneNumberString -> lookup phoneNumberString governmentalAgeDatabase)
getZip :: String -> Maybe [Int]
getZip phoneNumberString =
   lookup name phonebook >>==
      (\phoneNumberString -> lookup phoneNumberString governmentalZipCodeDatabase)
getTaxPaidYears :: String -> Maybe [Int]
getTaxPaidYears phoneNumberString =
   lookup name phonebook >>==
      (\phoneNumberString -> lookup phoneNumberString governmentalTaxYearDatabase)

现在,假设每个*Database都返回[Int]类型,第二个问题我们如何编写一个像lookupPersonsInformation这样的函数来返回来自输入字符串中输入内容的适当信息,并给出返回相应函数的查找,返回请求的信息?这就是我想要做的工作:

lookupAppropriateFunction :: [(String, String -> [Int])] --Here I want the second part
                                                   -- of the tuple to be the functions
lookupAppropriateFunction = [ ("age",   getAge),
                              ("zip",   getZip),
                              ("taxes", getTaxPaidYears) ]

lookupPersonsInformation :: String -> Maybe [Int]
lookupPersonsInformation nameAndInfo =
   lookup ( words nameAndInfo!!0 ) >>=
     ( \phoneNumberString -> lookup ( words nameAndInfo!!1 ) lookupAppropriateFunction )

-- >> lookupPersonsInformation "Bob age"
      [53]  --Bob's age
-- >> lookupPersonsInformation "Fred zip"
      [28202]  --Fred's age
-- >> lookupPersonsInformation "Alice taxes"
      [2010,2011,2013]  --Alice's paid taxes years, It looks like she skipped 2012 :)

很明显,错误会以Nothing的形式传播到最后,但我不确定如何将其应用于更高阶函数的下一步。是使用words进行解析还是在查找表的结构中更多,我想返回一个函数`

1 个答案:

答案 0 :(得分:0)

我最终选择了以下内容:

-------------------------------------------------------------------------
intPusher :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and tries to turn it into an Int, and push it onto the stack
intPusher word = case (reads word) of
  []       -> \stak -> Nothing
  [(x,"")] -> \stak -> Just (x:stak)
  [(x,y)]  -> \stak -> Nothing
-------------------------------------------------------------------------
dicLookup :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and looks it up in the dictionary
dicLookup word = case (lookup word wordsTable) of
  Nothing -> intPusher word
  Just f  -> f
-------------------------------------------------------------------------
wordsTable :: [(String, Stack -> Maybe Stack)]
-- ^ Checks the string against the commands
wordsTable = [ ("+", addIt)
               ,("-", subIt)
               ,("*", multIt)
               ,("/", divIt)
               ,("/MOD", modQuotIt)
               ,("MOD", modIt)
               ....
               ,("2DROP", drop2It) ]
-------------------------------------------------------------------------
interpretProgram :: String -> Maybe Stack

interpretProgram str = foldl (>>=) (Just[]) (map dicLookup (words str))

并且对于字典中的每个元组值,我提供了函数声明:

-------------------------------------------------------------------------
addIt :: Stack -> Maybe Stack
-- ^ Adds the first two elements of the stack
addIt stak = case stak of
  x:y:xs -> Just (x + y:xs)
  x:xs   -> Nothing
  _      -> Nothing
-------------------------------------------------------------------------
subIt :: Stack -> Maybe Stack
-- ^ Subtracts the first two elements of the stack
subIt stak = case stak of
  x:y:xs -> Just (y - x:xs)
  x:xs   -> Nothing
  _      -> Nothing
-------------------------------------------------------------------------
multIt :: Stack -> Maybe Stack
-- ^ Multiplies the first two elements of the stack
multIt stak = case stak of
  x:y:xs -> Just (x * y:xs)
  x:xs   -> Nothing
  _      -> Nothing

...

这可以通过取一个字符串,将其分解为单个单词' (如果可能的话,然后返回Nothing,如果它可以,然后传递到字典中以查找与字典中的键相比的单词的值,从而起到查找表的作用。如果单词是字典中的键,则返回值,该值是执行某些任务的高阶函数(就像单词function一样,如果高阶函数遇到错误,它将返回Nothing

在处理Monads时,只有两种类型的返回值。 Maybe AnyTypeNothingAnyType可以是模块中已声明的任何类型,也可以是Haskell中的任何基本类型(Int,Char,[Char]等...)。诀窍是返回Maybe AnyTypeNothing类型。由于Haskell需要对if语句进行终端声明,因此可以采用常规方法来捕获'任何潜在的错误,并传递“无所事事”。输入[grand]父函数的最终返回值。