簡體   English   中英

Haskell函數來自(a - > [b]) - > [a - > b]

[英]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)?

你可以概括seperateFuncsApplicative (或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

  1. (a -> fb) -> f (a -> b) ==> let t = (->) a
  2. 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功能,就沒有什么區別ApplicativeMonad 為什么? 好吧,我沒有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 = undefinedjoinFuncs = 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM