首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 ><$>算子和<*>算子的简单解释

<$>算子和<*>算子的简单解释
EN

Stack Overflow用户
提问于 2013-11-07 11:40:56
回答 4查看 422关注 0票数 4

我要(简单地)谈一谈耶苏德。是的,..。我也从未或真的很少使用haskell。大学lecturer.....huh。

所以我读了一本关于yesod的书,在一些章节中,作者使用了一些操作符,比如<$><*>。有人能用简单的话解释一下,这个操作符是做什么的?谷歌很难找到这样的图表,如果试图阅读Control.Applicative的文档,但老实说,对于一个haskell初学者来说很难找到。

因此,我希望任何人都能给我一个简单的答案:)

书中使用这些操作符的例子如下:

代码语言:javascript
复制
......
personForm :: Html -> MForm Handler (FormResult Person, Widget)
personForm = renderDivs $ Person
    <$> areq textField "Name" Nothing
    <*> areq (jqueryDayField def
        { jdsChangeYear = True -- give a year dropdown
        , jdsYearRange = "1900:-5" -- 1900 till five years ago
        }) "Birthday" Nothing
    <*> aopt textField "Favorite color" Nothing
    <*> areq emailField "Email address" Nothing
    <*> aopt urlField "Website" Nothing
data Person = Person
    { personName          :: Text
    , personBirthday      :: Day
    , personFavoriteColor :: Maybe Text
    , personEmail         :: Text
    , personWebsite       :: Maybe Text
    }
  deriving Show
.....

..

嘿,

非常感谢,令人惊讶的是,大多数答案都是有用的。可悲的是,只有一个答案才能“解决”。非常感谢,这个教程(我在Google上真的找不到)相当不错

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-11-07 12:02:54

如果您还没有准备好学习函子、应用程序和monads,这可能会给您一个如何使用<$><*>的直觉。(在我真正理解其他东西之前,我自己就通过看例子来学习如何使用它们。)如果没有<$><*>,代码的第一部分如下所示:

代码语言:javascript
复制
......
personForm :: Html -> MForm Handler (FormResult Person, Widget)
personForm = do
    name <- areq textField "Name" Nothing
    bday <- areq (jqueryDayField def
        { jdsChangeYear = True -- give a year dropdown
        , jdsYearRange = "1900:-5" -- 1900 till five years ago
        }) "Birthday" Nothing
    colour <- aopt textField "Favorite color" Nothing
    email <- areq emailField "Email address" Nothing
    url <- aopt urlField "Website" Nothing
    renderDivs $ Person name bday colour email url

换句话说,<$><*>可以消除创建许多我们只使用一次的符号的需要。

票数 3
EN

Stack Overflow用户

发布于 2013-11-07 11:54:41

我总是非常小心的时候,作出的答案,主要是由链接,但this is one amazing tutorial解释函子,应用程序,并给予一些理解的单一。

票数 9
EN

Stack Overflow用户

发布于 2013-11-07 13:31:49

当然,最简单的答案是类型。这些运算符来自类型类型Functor及其子类Applicative

代码语言:javascript
复制
class Functor f where
  fmap :: (a -> b) -> (f a -> f b)

(<$>) = fmap -- synonym

class Functor f => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

最简单的直观答案是,FunctorsApplicative允许您用“元数据”注释简单值,(<$>)(<*>)和朋友允许您转换“常规”值级函数来处理“注释”值。

代码语言:javascript
复制
go x y                    -- works if x and y are regular values
go <$> pure x <*> pure y  -- uses `pure` to add "default" metadata
                          -- but is otherwise identical to the last one

不过,就像任何简单的答案一样,这是个谎言。“元数据”是一个非常简化的术语。更好的是“计算上下文”或“效果上下文”或“容器”。

如果您熟悉Monad,那么您已经非常熟悉这个概念了。所有的Monad都是Applicative的,所以您可以认为(<$>)(<*>)为一些do表示法提供了另一种语法。

代码语言:javascript
复制
do x_val <- x                     go <$> x
   y_val <- y                        <*> y
   return (go x_val y_val)

它有较少的符号,并强调对两个参数“应用”go的概念,而不是强调“获取x生成的值,然后得到y生成的值,然后将这些值应用于go,然后像do语法那样重新包装结果”的概念。

我可以抛出的最后一个直觉是,以一种完全不同的方式来看待ApplicativeApplicative等价于另一个名为Monoidal的类。

代码语言:javascript
复制
class Functor f => Monoidal f where
  init :: f ()                             -- similar to pure
  prod :: f a -> f b -> f (a, b)           -- similar to (<*>)

以便Monoidal Functor允许您(a)用一个平凡的值实例化它们。

代码语言:javascript
复制
  init :: [()]
  init = []

  init :: Maybe ()
  init = Just ()

还把其中的两个人挤在一起生产他们的产品

代码语言:javascript
复制
  prod :: [a] -> [b] -> [(a, b)]
  prod as bs = [(a, b) | a <- as, b <- bs]

  prod :: Maybe a -> Maybe b -> Maybe (a, b)
  prod (Just a) (Just b) = (Just (a, b))
  prod _        _        = Nothing

这意味着,使用Monoidal函子,您可以将大量的值粉碎在一起,然后在整个簇上创建一个值级函数fmap

代码语言:javascript
复制
go <$> maybeInt `prod` (maybeChar `prod` maybeBool) where
  go :: (Int, (Char, Bool)) -> Double                       -- it's pure!
  go (i, (c, b)) = ...

这在本质上就是你对(<$>)(<*>)所做的,只是用更少的元组

代码语言:javascript
复制
go <$> maybeInt <*> maybeChar <*> maybeBool where
  go :: Int -> Char -> Bool -> Double
  go i c b = ...

最后,下面是两个概念之间的转换方式

代码语言:javascript
复制
-- forward
init     = pure ()
prod x y = (,) <$> x <*> y

-- back
pure a   = const a <$> init
f <*> x  = ($) <$> prod f x

这说明了如何将(<*>)视为采用正常值级应用程序($)并将其注入Functor内部的product中。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19834982

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档