Maybe参数的通用数据构造函数

马可

我有一堆数据结构,例如data Foo = Foo {a :: Type1, b :: Type2} deriving (Something)Type1Type2并且总是不同的(通常是原始类型,但无关紧要),并且数量也不同。

我来有很多功能,例如

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

什么是Applicatives?从本质上讲,它们是功能更强大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)。但是,<*>运算符使它们比Functors更强大它为您提供了一种将函数放入数据结构的方法,然后将该函数应用于同样包装在数据结构中的值。所以当你有类似的东西

> :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)使用justFunctorfmap,我们不能在其中应用任何内容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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Scala中构造函数的通用参数

来自分类Dev

通用作为构造函数的参数

来自分类Dev

数据实例的通用数据构造函数

来自分类Dev

让非通用类在构造函数中接受通用参数

来自分类Dev

数据构造函数的参数约束

来自分类Dev

从单个构造函数参数推断通用类类型参数

来自分类Dev

如何为任何数据构造函数编写通用函数?

来自分类Dev

如何构造Java通用类以接受非通用构造函数参数

来自分类Dev

将参数传递给通用Class类型的构造函数

来自分类Dev

具有实现接口的通用参数的Java构造函数

来自分类Dev

C#通用列表作为构造函数参数

来自分类Dev

在通用约束中通过构造函数传递参数

来自分类Dev

带有静态方法的Typescript通用类构造函数参数

来自分类Dev

C#通用列表作为构造函数参数

来自分类Dev

类的通用构造函数

来自分类Dev

通用构造函数

来自分类Dev

Swift通用构造函数

来自分类Dev

类的通用构造函数

来自分类Dev

PowerMockito模拟通用构造函数

来自分类Dev

Rust中的通用构造函数

来自分类Dev

通用数组构造函数

来自分类Dev

获取通用函数的参数

来自分类Dev

构造函数与数据字段不同的参数类型

来自分类Dev

C ++构造函数参数

来自分类Dev

构造函数默认参数

来自分类Dev

构造函数参数的条件

来自分类Dev

构造函数参数

来自分类Dev

复制构造函数的参数

来自分类Dev

LinearGradientBrush构造函数参数