![](/img/trans.png)
[英]Matching at least 1 of 3 Scala Regexes using an Applicative Functor
[英]Understanding Applicative Functor in Scala
假設我需要編寫一些函數來調用一些 REST API: api1
、 api2
、 api3
。
def api1(url: Url) = ???
def api2(url: Url) = ???
def api3(url: Url) = ???
假設為簡單起見,我使用自己的簡化類Url
:
case class Url(host: String, port: Int, path: Path)
為了構建一個Url
我從配置中讀取host
和port
並調用函數api1
、 api2
、 api3
,它們添加所需的paths
並調用它們的 API:
def api1(host: String, port: Int) = ???
def api2(host: String, port: Int) = ???
def api3(host: String, port: Int) = ???
val (host, port) = ... // read from the configuration
// call the APIs
api1(host, port)
api2(host, port)
api3(host, port)
為了隱藏host
和port
以及構造Url
其他細節,使用函數Path => Url
(或builder pattern
如果我們用Java
編寫)要好得多。
def api1(f: Path => Url) = ...
def api2(f: Path => Url) = ...
def api3(f: Path => Url) = ...
很容易實現這樣的函數f: Path => Url
with curring
val url: String => Int => Path = (Url.apply _).curried
val (host, port) = ... // from the configuration
val f = url(host, port)
api1(f)
api2(f)
api3(f)
到目前為止,一切都很好,但如果有可選的主機和端口怎么辦?
val (hostOpt: Option[String], portOpt: Option[Int]) = ... // from configuration
現在我們有一個函數String => Int => Path => Url
和Option[String]
和Option[Int]
。 如何獲得Path => Url
?
讓我們問一個稍微不同的問題:如何獲得Option[Path => Url]
給定String => Int => Path => Url
、 Option[String]
和Option[Int]
?
幸運的是,我們可以輕松定義這樣的操作:
trait Option[A] { ... def ap[B](of: Option[A => B]): Option[B] = ??? }
鑒於這個ap
我們可以回答原來的問題:
val of: Option[Path => Url] = portOpt ap (hostOpt ap Some(url)
of.map(f => api1(f))
of.map(f => api2(f))
of.map(f => api3(f))
抽象地說,我們使用了Option
是一個應用函子的事實。 如果M
是一個函子並且有兩個附加操作,則M
是一個應用函子:
ap
得到M[B]
給定M[A => B]
和M[A]
pure
從A => B
得到M[A => B]
( Some
for Option
)這些操作應該符合兩個簡單的規律,但這是另一回事。
...
是否有意義 ?
這對我來說聽起來很合理,雖然我不確定這里是否有很多問題,這是它自己的問題。
我將其作為答案而不是評論,因為有一件事情值得注意。 對於許多類型,有理由避免 monadic 綁定並堅持使用ap
不僅僅是“使用功能較弱的抽象是正確的做法”。
例如:標准庫未來 API 的zip
是一個應用運算符,它允許您並行運行期貨,如果您使用bar() zip foo()
而不是for { f <- foo(); b <- bar() } yield (f, b)
for { f <- foo(); b <- bar() } yield (f, b)
你實際上可以加速你的程序(在很多情況下)。 對於其他類型,使用 applicative functor 的東西而不是 monadic bind 提供了其他類型的優化可能性。
Option
的情況並非如此。 根據flatMap
定義ap
並非不合理。 使用應用性組合子仍是“做正確的事”,但flatMap
就在那里,不需要額外的定義或依賴和for
-comprehensions是如此簡單和干凈。 對於期貨之類的東西,您看到的回報並不相同。
在他們的書 'Finding Success (and Failure) with Haskell' 中,Julie Moronuki 和 Chris Martin 有一個很好的例子來理解 Applicative 和 Monad 之間的區別 - 我發現它非常有用,因此我基於以下幻燈片:https:/ /www.slideshare.net/pjschwarz/applicative-functor-part-2 。
在其中,我將運行示例翻譯成 Scala。
這是他們的程序開始的方式,在他們開始從任一個 Monad 到驗證應用程序的過程之前:
檢查一下,看看他們如何轉換/改進代碼(下載以獲得最佳質量)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.