我遇到这种情况:
import Control.Monad.Except
data Foo = Foo { i :: Int }
data Bar = Bar { i :: Int , v: Char }
emptyFoo = Foo 0
emptyBar = Bar 0 'N'
extractF :: (Except String Foo) -> Foo
extractF ex = either (const emptyFoo) id (runExcept ex)
extractB :: (Except String Bar) -> Bar
extractB ex = either (const emptyBar) id (runExcept ex)
有没有办法将上面的extract
函数概括为一个,如:
myfoo = extract someFooInstanceWrappedInException
mybar = extract someBarInstanceWrappedInException
答案 0 :(得分:3)
您可以声明一个提供默认值的类
-- Note: consider using Data.Default instead of creating your own class.
class Default a where
def :: a
instance Default Foo where
def = Foo 0
instance Default Bar where
def = Bar 0 'N'
extract :: Default a => Except String a -> a
extract ex = either (const def) id (runExcept ex)
答案 1 :(得分:3)
由于Except e
是Foldable
的实例,您可以为您的类型定义Monoid
个实例并使用fold :: (Foldable f, Monoid m) => f m -> m
。
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Monoid
newtype Foo = Foo { getFoo :: Sum Int } deriving Monoid
extractFoo :: Except e Foo -> Foo
extractFoo = fold
我完全不知道你的类型是什么意思,所以我只是用Sum
给出了一个例子。 Monoid
实例的正确语义将是特定于域的(并且您的类型甚至可能不是有效的Monoid
)。但是这个想法是mempty
将是你的默认值;由于Except e m
包含零个或m
个,fold
会插入默认值(如果它为空)。