2013-08-23 58 views
0

我正在學習Scalaz 7,類型類系統太抽象了,有一件我不明白的就是爲什麼Bind.ap是以這樣的方式由bind實現的。爲什麼Bind.ap是通過Bind.bind在Scalaz中實現的7

trait Apply[F[_]] extends Functor[F] { self => 
    def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] 
.... 
} 


trait Bind[F[_]] extends Apply[F] { self => 
    /** Equivalent to `join(map(fa)(f))`. */ 
    def bind[A, B](fa: F[A])(f: A => F[B]): F[B] 

    override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = bind(f)(f => map(fa)(f)) 
    .... 
} 

我知道我們可以把F[A => B]F[C],所以bind有意義的第一個參數,但第二個參數需要A => F[B],怎麼f => map(fa)(f)相當於A => F[B]

回答

3

我知道我們可以對待F[A => B]作爲F[C]

所以CA => B。我們稱之爲事實1

讓我們改寫bind具有與d C和B代替A,所以我們不要被碰撞類型參數變量困惑:

def bind[C, D](fc: F[C])(f: C => F[D]): F[D] 

所以f論點的bind第二個參數列表中有爲C => F[D],其可以寫成(A => B) => F[D](使用事實1)。請注意,它在bind(f)(f => ...),第二個f只是一個lambda參數(這恰好是一個函數),而第一個f不是函數。它可能已被寫入bind(f)(fun => map(fa)(fun))

f => map(fa)(f)怎麼樣相當於A => F[B] ??

那麼,它不是...... f => map(fa)(f)必須鍵入爲(A => B) => F[D]。所以

  • f類型爲A => B
  • faF[A]型的,也就是在ap第一個參數列表中fa - 不綁定
  • 綜觀map定義,map(fa)(f)將是類型F[B]

這意味着

(A => B) => F[D] 
    f  => map(fa)(f) 
(A => B) => F[B] 
// D is really B 

所以bind(f)(f => map(fa)(f))F[B]類型是什麼需要ap的...

可能這使得它更清晰,概念上,這是怎麼回事:

def ap[A, B](m_elem: => F[A])(m_fun: => F[A => B]): F[B] = 
    for { 
    fun <- m_fun 
    elem <- m_elem 
    } yield { 
    fun(elem) 
    } 
//To hammer it home, same as: m_fun.flatMap(fun => m_elem.map(elem => fun(elem))) 
+0

謝謝,這真的很有幫助。最容易混淆的部分是'bind(f)(f => map(fa)(f))'的第二個參數的名稱,應該改爲'bind(f)(g => map(fa) )' – smilingleo

1

正如您從bind方法簽名中可以看到的,這只是一個自命名的Haskell命名方式flatMap函數。所以Bind特徵爲Monad提供了必要的flatMap

也許會更容易理解,如果我們採取List[Int => String],而不是F[A => B],還等什麼bind做它從列表中的每個功能,讓我們說我們有以下列表:List((x: Int) => (x + 1).toString)f參數和List(1,2)fa參數ap方法,並將f自變量(ListInt => String函數)的每個函數應用於參數fa的每個值(ListInt)。

所以上答案如何爲f =>地圖(FA)(F)相當於A => F [B]A在這個代碼是從fList一個Int => String功能,當你映射來自一些值faListF[B],這將是類型String

相關問題