gpt4 book ai didi

haskell - Yesod应用形式

转载 作者:行者123 更新时间:2023-12-02 16:48:48 27 4
gpt4 key购买 nike

我尝试了一下 Yesod,出现了一个问题:如何将表单用作 Applicatives?

采取:

    personForm :: Html -> MForm Synopsis Synopsis (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

我不明白<*>是怎么做的运算符,据我了解,它需要 f (a -> b) 类型的东西(即包含二元函数的仿函数)作为其第一个参数,被应用于 AForm值:

(AForm f) <*> (AForm g) = AForm $ \mr env ints -> do ...

这是怎么回事?

https://github.com/yesodweb/yesod/blob/bf293e6a1f6e691281520d254f72b9441cc64704/yesod-form/Yesod/Form/Types.hs#L95

最佳答案

如果您尝试稍微忽略详细类型并着眼于大局,这会有所帮助。

想想<$><*>作为 $ 的特殊版本在不同的层面上工作。

一般应用仿函数

让我们先看看一般情况 - 假设我有一个应用仿函数 AF和对象

x :: AF a
y :: AF b
z :: AF c

有点意思是他们“做某事”然后返回 a 类型的值, bc ,也是一个纯函数

f :: a -> b -> c -> d

我想用它来将这些值组合在一起以获得 d 。然后

f <$> x <*> y <*> z    :: AF d

通过“做”来工作x ,然后y然后z ,并申请f到结果。

请注意,这类似于 f $ a $ b $ c .

如果您的应用仿函数与 monad 实例一致,f <$> x <*> y <*> z是一种很好的写作方式

do
a <- x
b <- y
c <- z
return (f a b c)

作为应用仿函数的形式

将表单视为生成数据(来自用户)的东西。 areqaopt两者都返回 AForm sub master ?? 。您可以忽略 submaster - 它们用于使用类型系统跟踪站点/子站点。 ??是返回的数据类型。

所以
areq textField "Name" Nothing是一个小形式,生成 Text ,
areq (jqueryDayField def) "Birthday" Nothing是一个小形式,生成 Day ,
另外三个也产生Text .

现在我们有了

data Person = Person Text Day Text Text Text

这样Person是一个函数:: Text -> Day -> Text -> Text -> Text -> Person ,所以如果你有

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

您已将所有这些表单合并为一个表单,生成一个 Person值,通过获取字段的所有单独值并应用纯 Person对他们起作用。

要以单子(monad)风格编写,您需要编写

do
name <- areq textField "Name" Nothing
day <- areq (jqueryDayField def
{ jdsChangeYear = True -- give a year dropdown
, jdsYearRange = "1900:-5" -- 1900 till five years ago
}) "Birthday" Nothing
color <- aopt textField "Favorite color" Nothing
email <- areq emailField "Email address" Nothing
website <- aopt urlField "Website" Nothing

return $ Person name day color email website

我非常喜欢应用仿函数风格,因为它感觉就像将函数应用于某些数据,而不是执行一系列指令。

那么 <$> 是怎么回事?与 <*>

你可能已经注意到我总是这样做

pureFunction <$> af1 <*> af2 <*> af3 <*> af4 ....

<$>首先,和<*>对于其余的。那是因为第一件事,pureFunction是纯粹的,不适用于应用仿函数值。它把它举起来。 (所有应用仿函数都是仿函数。)让我们比较一下类型:

<$> :: Functor f     =>    (a -> b) -> f a -> f b
<*> :: Applicative f => f (a -> b) -> f a -> f b

这意味着 <$>用于提升纯函数,但是当您使用 <*> 时左侧必须已经生成函数而不仅仅是数据,这最初看起来很奇怪,但如果您使用 <$> 则不然第一的。例如,如果您部分应用 (++)"Hello"你得到一个函数 :: String -> String ,所以

         getLine             :: IO String             -- produces a String
(++) <$> getLine :: IO (String -> String) -- produces an appender
(++) <$> getLine <*> getLine :: IO String -- produces a combined String

比较一下

areq textField "Name" Nothing
:: AForm sub master Text

Person :: Text -> Day -> Text -> Text -> Text -> Person ,如果我们给它 name::Text值,我们得到一个部分应用的函数Person name类型 Day -> Text -> Text -> Text -> Person

Person <$> areq textField "Name" Nothing
:: AForm sub master (Day -> Text -> Text -> Text -> Person)

我们可以使用 <*> 进行组合产生 Day 的东西给出产生 (Text -> Text -> Text -> Person) 的东西,依此类推,直到我们得到产生 Person 的东西。 。 (这一切都有效,因为 -> 关联到右侧,而 <$><*> 关联到左侧,就像 $ 一样。)

关于haskell - Yesod应用形式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15869376/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com