2009-10-28 35 views
29

根據the Typeclassopedia(其它來源之一),Applicative邏輯MonadPointed(因此Functor)之間所屬的類型的類層次結構,所以我們非常有這樣的事情,如果Haskell的前奏是今天寫的:可以liftM與liftA不同嗎?

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

class Functor f => Pointed f where 
    pure :: a -> f a 

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

class Applicative m => Monad m where 
    -- either the traditional bind operation 
    (>>=) :: (m a) -> (a -> m b) -> m b 
    -- or the join operation, which together with fmap is enough 
    join :: m (m a) -> m a 
    -- or both with mutual default definitions 
    f >>= x = join ((fmap f) x) 
    join x = x >>= id 
    -- with return replaced by the inherited pure 
    -- ignoring fail for the purposes of discussion 

(如果這些默認的釋義是我從explanation at Wikipedia重新輸入,錯誤的是我自己的,但如果有錯誤,它至少在原則上可能的)

由於庫目前的定義,我們有:

liftA :: (Applicative f) => (a -> b) -> f a -> f b 
liftM ::  (Monad m) => (a -> b) -> m a -> m b 

和:

(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b 
ap ::  (Monad m) => m (a -> b) -> m a -> m b 

注意這些類型的每對之間的相似性。

我的問題是:liftM(從liftA不同)和ap(從<*>不同),只需將歷史現實Monad不是設計時考慮PointedApplicative的結果?或者他們是否以某種其他行爲方式(可能對某些合法的Monad定義)區別於僅需要Applicative上下文的版本?

如果它們是不同的,你可以提供一組簡單的定義(服從的Monad需要ApplicativePointed的法律,以及在Typeclassopedia描述Functor定義和其他地方而不是由類型系統執行)針對liftAliftM表現不同?

或者,如果它們不明顯,您是否可以使用這些相同的法律來證明它們的等價性?

回答

22

liftAliftMfmap.應該都是相同的功能,而且他們必須,如果他們滿足函子法:

fmap id = id 

然而,這不是由哈斯克爾檢查。

現在申請。對於某些函數,ap<*>可能是不同的,因爲可能有多個實現滿足類型和法則。例如,List有多個可能的Applicative實例。

instance Applicative [] where 
    (f:fs) <*> (x:xs) = f x : fs <*> xs 
    _  <*> _  = [] 
    pure    = repeat 

ap功能仍然被定義爲liftM2 id,這是免費的午餐每MonadApplicative比如:你可以如下聲明應用性。但是在這裏,您有一個具有多個Applicative實例的類型構造函數的示例,它們都符合法律。但是如果你的monad和你的應用函子不同意,那麼爲他們設置不同的類型被認爲是很好的形式。例如,上面的Applicative實例與[]的monad不一致,所以您應該真的說newtype ZipList a = ZipList [a],然後爲ZipList而不是[]創建新實例。

+2

好的,的確,對於某些類型,有多個Applicative實例和多個Monad實例。但是,在上面的定義下,pure/return實現將不得不在應用實例和Monad實例之間共享。這是否意味着,爲了滿足法律,<*>和ap必須是相同的?它看起來像你的例子依賴使用pure = repeat爲[]創建Applicative實例,但對於[] with return =([])仍然使用Prelude Monad實例? – 2009-10-28 04:45:34

+1

我可能會錯過一些東西,但它不是真的,類型'forall a,b。 (a - > b) - > F a - > F b'確保爲'fmap'。例如,考慮'notmap f xs = zipWith($)(repeat(const。f $ head xs))xs'。 – 2011-05-02 11:54:06

+1

@Apocalisp:只給出fmap的類型,你仍然可以擁有異國情調的成員。邊條件fmap id = id足以強制這個問題,我認爲你在'f'中加入的額外量詞是作弊的。 ;)Doug,儘管Functor的定義在給定法律時是唯一的,但適用法律足夠寬鬆以允許多個符合的定義。但是,按照慣例,給定類型的Monad和Applicative應該兼容。 – 2012-05-15 02:32:43

8

他們可以不同,但他們不應該

它們可以有所不同,因爲它們可以有不同的實現:一個在instance Applicative中定義,另一個在instance Monad中定義。但如果它們確實不同,那麼我會說編寫這些實例的程序員寫了誤導性的代碼。

你是對的:功能的存在與他們歷史原因一樣。人們對事情本來應該是有強烈的想法。

相關問題