[英]Haskell function from (a -> [b]) -> [a -> b]
我有一個函數seperateFuncs
這樣的
seperateFuncs :: [a -> b] -> (a -> [b])
seperateFuncs xs = \x -> map ($ x) xs
我想知道反過來是否存在,即是否存在功能
joinFuncs :: (a -> [b]) -> [a -> b]
我認為不是(主要是因為列表不是固定的長度),但也許我會被證明是錯的。 那么問題是有一些數據類型f
有一個函數::(a - > fb) - > f(a - > b)?
你可以概括seperateFuncs
以Applicative
(或Monad
)漂亮干凈:
seperateFuncs :: (Applicative f) => f (a -> b) -> (a -> f b)
seperateFuncs f x = f <*> pure x
用無點樣式編寫,你有seperateFuncs = ((. pure) . (<*>))
,所以你基本上想要unap . (. extract)
unap . (. extract)
。extract unap . (. extract)
,如果以有點的方式編寫,則給出以下定義:
joinFuncs :: (Unapplicative f) => (a -> f b) -> f (a -> b)
joinFuncs f = unap f (\ g -> f (extract g))
在這里,我將Unapplictaive
定義為:
class Functor f => Unapplicactive f where
extract :: f a -> a
unap :: (f a -> f b) -> f (a -> b)
要獲得leftaroundabout給出的定義 ,您可以提供以下實例:
instance Unapplicative [] where
extract = head
unap f = [\a -> f [a] !! i | i <- [0..]]
instance Unapplicative ((->) c) where
extract f = f undefined
unap f = \x y -> f (const y) x
我認為對於任何不像(->)
f
,很難想出一個“有用的”函數f :: (fa -> fb) -> f (a -> b)
(->)
。
首先,你可以蠻力強迫自己這個功能:
joinFuncs f = [\x -> f x !! i | i<-[0..]]
但這顯然很麻煩 - 結果列表總是無限的但是如果length(fx) > i
則僅用x
評估第i
個元素。
給出一個“真實”的解決方案
那么問題是有一些數據類型
f
有一個函數:: (a -> fb) -> f (a -> b)
?
考慮(->)c
。 這樣,您的簽名讀取(a -> (c->b)) -> (c->(a->b))
或等效地(a -> c -> b) -> c -> a -> b
事實證明,這只是flip
。
當然,這是一個微不足道的,因為seperateFuncs
具有相同的簽名類型...
“是否有一些數據類型f具有函數::(a - > fb) - > f(a - > b)?”
事實上,在Traversable類型類中有一個更通用的版本,它處理可交換的仿函數:
class (Functor t, Foldable t) => Traversable t where
...
sequenceA :: Applicative f => t (f b) -> f (t b)
這與你的功能有什么關系? 從您的類型開始,使用一種類型替換,我們恢復sequenceA
:
(a -> fb) -> f (a -> b)
==> let t = (->) a
t (fb) -> f (tb)
但是,這種類型具有t
必須是Traversable的約束 - 並且(->) a
沒有Traversable實例,這意味着通常不能使用函數來完成此操作。 雖然注意到“其他方向” - f (a -> b) -> (a -> fb)
適用於所有函數和所有Applicatives f
。
我最近不得不考慮一些與你的問題非常相似的問題。 這是我發現的概括。
首先,這是微不足道的(在Tinctorius指出):
f2m :: Functor f => f (a -> b) -> a -> f b
f2m f a = fmap ($a) f
但一般來說這是不可能做到的:
m2a :: Monad m => (a -> m b) -> m (a -> b)
理解這一點,這人在#haskell IRC頻道親切地向我解釋一個有見地的方式是,如果存在着一個m2a
功能,就沒有什么區別Applicative
和Monad
。 為什么? 好吧,我沒有100%跟隨它,但它是這樣的: Monad m => a -> mb
是一個參數的常見類型的monadic動作,而Applicative f => f (a -> b)
是這也是非常常見的類型,因為不知道正確的名稱,我會稱之為“適用的應用程序”。 事實上Monad
可以做的事情是Applicative
不能與m2a
不存在的事實聯系在一起。
現在,適用於您的問題:
joinFuncs :: (a -> [b]) -> [a -> b]
我懷疑同樣的“Monad / = Applicative”論點(再次,讓我強調,我不完全理解)應該在這里適用。 我們知道Monad []
實例可以執行Applicative []
實例無法做到的事情。 如果你可以用指定的類型編寫一個joinFuncs
,那么[a -> b]
結果在某種意義上必須與a -> [b]
參數相比“丟失信息”,因為否則Applicative []
與Monad []
相同Monad []
。 (並且通過“丟失”信息我的意思是任何具有joinFuncs
類型的函數都不能有逆,因此它保證消除某些函數對f, g :: a -> [b]
之間的區別。 joinFuncs = undefined
是joinFuncs = undefined
。)
我確實發現我需要類似於m2a
功能所以我發現的特殊情況是可以這樣做:
import Data.Map (Map)
import qualified Data.Map as Map
-- | Enumerate a monadic action within the domain enumerated by the
-- argument list.
boundedM2a :: Monad m => (a -> m b) -> [a] -> m [(a,b)]
boundedM2a f = mapM f'
where f' a = do b <- f a
return (a, b)
-- | The variant that makes a 'Map' is rather useful.
boundedM2a' :: (Monad m, Ord a) => (a -> m b) -> [a] -> m (Map a b)
boundedM2a' f = liftM Map.fromList . boundedM2a f
請注意,除了我們列舉a
的要求之外,一個有趣的觀察是,要做到這一點,我們必須在某種意義上“實現”結果; 將它從函數/動作轉換為某種列表,地圖或表格。
問題“我可以使用類型簽名joinFuncs :: (a -> [b]) -> [a -> b]
函數是不完整的,但沒有說明你希望這個函數滿足哪些法則。沒有法律,你可以解決這個問題定義joinFuncs _ = []
(總是返回一個空列表)的問題。這個簡單的函數滿足所需的類型簽名,但很可能沒用。
要求joinFuncs
有用的一種方法是強加非簡並定律, separateFuncs . joinFuncs == id
separateFuncs . joinFuncs == id
。 然后可以證明為這種類型的簽名實現joinFuncs
是不可能的。
這種類型簽名的更一般情況是(a -> fb) -> f (a -> b)
其中f
是一些仿函數。 我稱這些仿函數“僵硬”。 看到這個問題這個算子的屬性是否比monad更強? 更多細節。
所有剛性函子R
滿足R ()
類型只有一個不同值的屬性,即它等價於()
。 這允許我們立即看到List
仿函數不是嚴格的,因為List ()
不等同於()
。
剛性函子的最簡單的非平凡例子是type R a = (a -> p) -> a
其中p
是固定類型。 以這種方式定義的仿函數R
實際上是一個剛性的monad。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.