1

I'm trying to use Data.Map to map strings to functions. The issue I'm having is that the main error handling in my program uses an Either monad, and Map.lookup will return Maybe ([SomeVal] -> Either ValError SomeVal). How can I make Map.lookup play nicely with the Either monad in this case?

apply :: String -> [SomeVal] -> Either ValError SomeVal
apply s args = (Map.lookup s prims) >>= \fn -> fn args

prims :: Map String ([SomeVal] -> Either ValError SomeVal)
prims = Map.fromList
    [("key", function)
    ,("key2", function2)
    ]

::> apply "key" [val1, val2, val3]
4

3 回答 3

8

这个Control.Error有一个很好的功能

note :: e -> Maybe a -> Either e a
note e Nothing  = Left e
note _ (Just a) = Right a

这对于将类似故障“升级”为Maybe类似故障很有用Either

lookupNote :: k -> Map.Map k v -> Either ValError v
lookupNote k = note (Missing k) . lookup k

它还有许多其他类似的方法,用于在和通用实例的转换器之间Either进行Maybe映射MonadPlus。我强烈推荐那个包。

于 2013-11-11T05:39:55.673 回答
6

其他答案已经解释了如何Maybe变成Either一般。但是,具体而言,您可以使用Data.Map代替,它不会包含在 a 中,并允许您选择如何处理不存在的键。Map.lookupMap.findWithDefaultMaybe

于 2013-11-11T06:00:37.587 回答
1

这取决于你想如何处理这个Nothing案子。如果您想断言密钥将永远存在(一个坏主意)

import Data.Maybe
apply s args = (prims ! s) args

但更聪明的方法是在没有发现任何东西的情况下拥有一个理智的值。可能你会想要一些ValError构造函数

ValError = ...
         | NoKey String
         ...
apply s args = maybe (Left $ NoKey s) ($args) $ M.lookup s prims

或者只想保留Maybe

apply :: String -> [SomeVal] -> Maybe (Either ValError SomeVal)

在未找到密钥的情况下,这些方法中的任何一种都提供了更明智的语义。您选择的主要是偏好,如果您打算制作applyAPI 的一个非常基本的部分以至于ValErrors 应该知道它,那么 1 效果很好。

否则,使用 2 会更痛苦,但不需要更改任何令人愉快的现有代码。

于 2013-11-11T05:18:16.000 回答