好了,讓我們考慮這樣的事情可能被簡化的方式。非一元版本將我想看看像const' f a = const a (f a)
,這顯然等同於flip const
有更具體的類型。隨着單子版本,然而,f a
結果可以做任意的事情仿函數的非參數結構(即,內容通常被稱爲「副作用」),包括取決於a
價值的東西。這告訴我們的是,儘管假裝就像我們放棄f a
的結果一樣,但我們實際上並沒有採取任何行動。返回a
不變的仿函數的參數部分遠不如必要的,我們可以用別的東西代替return
,仍然有一個概念上類似的功能。
因此,我們可以得出結論的第一件事是,它可以被看作是像下面這樣的功能的一個特殊情況:
doBoth :: (Monad m) => (a -> m b) -> (a -> m c) -> a -> m c
doBoth f g a = f a >> g a
從這裏,有兩種不同的方式來尋找的底層結構某種。
一種觀點是承認分割多個功能中的一個參數的圖案,然後重新組合的結果。這是由Applicative
/Monad
實例爲功能體現的概念,像這樣:
doBoth :: (Monad m) => (a -> m b) -> (a -> m c) -> a -> m c
doBoth f g = (>>) <$> f <*> g
...或者,如果你喜歡:
doBoth :: (Monad m) => (a -> m b) -> (a -> m c) -> a -> m c
doBoth = liftA2 (>>)
當然,liftA2
相當於liftM2
所以,如果取消對單子的操作到另一個單子都有事做單子變壓器你可能想知道;一般的關係,有尷尬,但在這種情況下,它的工作原理很容易,讓這樣的事情:
doBoth :: (Monad m) => ReaderT a m b -> ReaderT a m c -> ReaderT a m c
doBoth = (>>)
...模適當的包裝和這樣當然。要專門回到您的原始版本,return
的原始使用現在需要ReaderT a m a
類型,這不應該太難以識別爲讀取器單元的ask
函數。
另一透視是要認識到與類型,如(Monad m) => a -> m b
功能可直接組成,很像純函數。函數(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
給出了等價於函數組合(.) :: (b -> c) -> (a -> b) -> (a -> c)
的直接函數,或者您也可以使用Control.Category
和newtype
包裝函數Kleisli
以通用方式處理同一事物。但是,我們仍然需要分解參數,所以我們真正需要的是一個「分支」組合,其單獨不具有Category
;通過使用Control.Arrow
以及我們得到(&&&)
,讓我們重寫功能如下:
doBoth :: (Monad m) => Kleisli m a b -> Kleisli m a c -> Kleisli m a (b, c)
doBoth f g = f &&& g
由於我們不關心第一Kleisli箭頭的結果,只是它的副作用,我們可以放棄的一半元組中的顯而易見的方式:
doBoth :: (Monad m) => Kleisli m a b -> Kleisli m a c -> Kleisli m a c
doBoth f g = f &&& g >>> arr snd
這讓我們回到通用形式。專業你原來,return
現在變得簡單id
:
constKleisli :: (Monad m) => Kleisli m a b -> Kleisli m a a
constKleisli f = f &&& id >>> arr snd
由於常規功能也Arrow
S,上述定義在那裏工作,以及如果你推廣的類型簽名。然而,它可以是有啓發擴大導致純函數的定義和簡化如下:
\f x -> (f &&& id >>> arr snd) x
\f x -> (snd . (\y -> (f y, id y))) x
\f x -> (\y -> snd (f y, y)) x
\f x -> (\y -> y) x
\f x -> x
。
所以我們回到flip const
,正如所料!
總之,你的功能是在任(>>)
或flip const
一些變化,但在依賴於不同的方式 - 同時使用ReaderT
環境和基礎單子的(>>)
前者,後者使用特定的Arrow
的隱含副作用和期望Arrow
副作用以特定順序發生。由於這些細節,不可能有任何通用化或簡化可用。從某種意義上說,你使用的定義非常簡單,這就是爲什麼我給出的替代定義更長和/或涉及一定數量的打包和解包。
這樣的功能將是一個自然的除了某種形式的「單子工具庫」。雖然Control.Monad
提供了一些結合在一起的線程,但它並非詳盡無遺,我也不能在標準庫中找到或回想這個函數的任何變化。但是,如果在一個或多個實用程序庫中發現它,我一點都不會感到驚訝。
已經大多與存在的問題,分配,我真的不能提供關於命名超越你可以從上述有關相關概念的討論採取什麼太多指導。
作爲最後的一邊,還請注意,你的函數具有基於一個一元表達式的結果沒有控制流的選擇,因爲在執行表達式不管是主要目標。擁有獨立的參數內容的計算結構(即a
型的Monad m => m a
的東西),通常是你實際上並不需要一個完整的Monad
,並可能與Applicative
更普遍的概念獲得通過的標誌。
似乎可以使用普通的仿函數定義此函數:'constF ::函子F =>(A - >爲F b) - >一 - > F A; constF f a = a <$ f a' – fuz
@FUZxxl,這也可以,謝謝...這是常量名稱的正確用法呢? –
你是什麼意思? – fuz