這是可以定義一個函數mapProduct
,對於任何功能參數數量的工作原理:
{-# LANGUAGE FlexibleInstances, TypeFamilies #-}
module MapProduct (
mapProduct
) where
import Control.Monad
newtype ProdFuncList a b = ProdFuncList [ a -> b ]
class MapProdResult p where
type MapProdArg p
apNext :: ProdFuncList x (MapProdArg p) -> [x] -> p
instance (MapProdResult b) => MapProdResult ([a] -> b) where
type MapProdArg ([a] -> b) = (a -> MapProdArg b)
apNext (ProdFuncList fs) = apNext . ProdFuncList . ap fs
instance MapProdResult [b] where
type MapProdArg [b] = b
apNext (ProdFuncList fs) = ap fs
mapProduct :: (MapProdResult q) => (a -> MapProdArg q) -> [a] -> q
mapProduct f = apNext (ProdFuncList [f])
這是在行動:
> :l MapProduct.hs
[1 of 1] Compiling MapProduct (MapProduct.hs, interpreted)
Ok, modules loaded: MapProduct.
> mapProduct (+10) [1..4] :: [Int]
[11,12,13,14]
> mapProduct (*) [1..4] [10..12] :: [Int]
[10,11,12,20,22,24,30,33,36,40,44,48]
> mapProduct (\a b c -> a:b:c:[]) "bcs" "ao" "dnt" :: [String]
["bad","ban","bat","bod","bon","bot","cad","can","cat","cod","con","cot","sad","san","sat","sod","son","sot"]
這種方法的缺點是你很可能不得不鍵入註釋結果(如上面的例子所示)。這將是更地道簡單地使用fmap
和ap
直接:
> :m + Control.Monad
> (+10) `fmap` [1..4]
[11,12,13,14]
> (*) `fmap` [1..4] `ap` [10..12]
[10,11,12,20,22,24,30,33,36,40,44,48]
> (\a b c -> a:b:c:[]) `fmap` "bcs" `ap` "ao" `ap` "dnt"
["bad","ban","bat","bod","bon","bot","cad","can","cat","cod","con","cot","sad","san","sat","sod","son","sot"]
這不需要類型的註釋,並完全通用於所有的單子,而不僅僅是[]
。
(以上MapProduct模塊可以很容易地概括了所有的單子也是如此。我沒有以使其清楚地解決原來的問題。)
我猜這原本不是一個Haskell問題,因爲沒有訴諸存在類型的Haskell中不存在異類列表。 – Chuck 2010-03-23 15:07:26
我知道這個問題,但我認爲肯定可以解決這個問題,不是這樣嗎?這是一個非常簡單而有用的功能,它也很容易正確實施。 – levy 2010-03-23 15:31:33
爲什麼這是一個「測驗」? – MtnViewMark 2010-03-23 20:12:13