我有一堆数据结构,例如data Foo = Foo {a :: Type1, b :: Type2} deriving (Something)
和Type1
,Type2
并且总是不同的(通常是原始类型,但无关紧要),并且数量也不同。
我来有很多功能,例如
justFooify :: Maybe Type1 -> Maybe Type2 -> Maybe Foo
justFooify f b =
| isNothing f = Nothing
| isNothing b = Nothing
| otherwise = Just $ Foo (fromJust f) (fromJust b)
有什么我想念的吗?在我写了第三个这样的函数之后,我开始觉得也许可能太多了。
您需要应用剂!
import Control.Applicative
justFooify :: Maybe Type1 -> Maybe Type2 -> Maybe Foo
justFooify f b = Foo <$> f <*> b
或者您可以liftA2
在此示例中使用:
justFooify = liftA2 Foo
它的行为就像liftM2
,但对于Applicative
。如果您有更多参数,请使用更多<*>
s:
data Test = Test String Int Double String deriving (Eq, Show)
buildTest :: Maybe String -> Maybe Int -> Maybe Double -> Maybe String -> Maybe Test
buildTest s1 i d s2 = Test <$> s1 <*> i <*> d <*> s2
什么是Applicative
s?从本质上讲,它们是功能更强大Functor
和功能更弱的一种Monad
,它们介于两者之间。类型类的定义是
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
-- plus a few more things that aren't important right now
如果您Applicative
也是Monad
,则pure
与相同return
(实际上,有些人认为拥有return
是不正确的,我们应该只拥有pure
)。但是,<*>
运算符使它们比Functor
s更强大。它为您提供了一种将函数放入数据结构的方法,然后将该函数应用于同样包装在数据结构中的值。所以当你有类似的东西
> :t Test -- Our construct
Test :: String -> Int -> Double -> String -> Test
> :t fmap Test -- also (Test <$>), since (<$>) = fmap
fmap Test :: Functor f => f String -> f (Int -> Double -> String -> Test)
我们看到它在的内部构造了一个函数Functor
,因为Test
它带有多个参数。所以Test <$> Just "a"
有型Maybe (Int -> Double -> String -> Test)
。使用justFunctor
和fmap
,我们不能在其中应用任何内容Maybe
,但是<*>
可以。每个的应用对<*>
内部都应用一个参数Functor
,现在应该认为是一个参数Applicative
。
另一个方便的地方是它可以与所有Monad(当前定义其Applicative
实例)一起使用。这意味着列出,IO
一个参数的函数Either e
,解析器等。例如,如果您从用户那里获取输入以构建一个Test
:
askString :: IO String
askInt :: IO Int
askDouble :: IO Double
-- whatever you might put here to prompt for it, or maybe it's read from disk, etc
askForTest :: IO Test
askForTest = Test <$> askString <*> askInt <*> askDouble <*> askString
而且仍然可以。这就是应用程序的力量。
仅供参考,GHC 7.10中将实施Functor-Applicative-Monad提案。这将改变的定义,Monad
从
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
到
class Applicative m => Monad m where
return :: a -> m a
return = pure
(>>=) :: m a -> (a -> m b) -> m b
join :: m (m a) -> m a
(或多或少)。这将破坏一些旧的代码,但是许多人对此感到兴奋,因为这将意味着所有Monads是Applicatives,而所有Appadatives是Functor,而我们将拥有这些代数对象的全部功能。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句