2010-03-23 49 views
2

我不是一個Haskell程序員,但我很好奇以下問題。Haskell測驗:一個簡單的函數

非正式功能規格:

設MapProduct是一個函數,稱爲F和多個列表功能。它返回一個列表,其中包含每個可能組合中每個列表的調用F的結果。

例子:

其中F是簡單地返回它的參數,和兩個列表列表的功能調用MapProduct。其中一個列表包含整數1和2,另一個包含字符串「a」和「b」。它應該返回一個包含列表的列表:1和「a」,1和「b」,2和「a」,2和「b」。

問題:

  • 如何MapProduct實施?
  • 函數的類型是什麼?什麼是F的類型?
  • 我們可以通過查看它的類型來猜測函數的功能嗎?
  • 你可以處理非均勻列表作爲輸入嗎? (例如,輸入列表中的1和「a」)
  • 您需要引入什麼額外限制(如果有)來實現MapProduct?
+1

我猜這原本不是一個Haskell問題,因爲沒有訴諸存在類型的Haskell中不存在異類列表。 – Chuck 2010-03-23 15:07:26

+0

我知道這個問題,但我認爲肯定可以解決這個問題,不是這樣嗎?這是一個非常簡單而有用的功能,它也很容易正確實施。 – levy 2010-03-23 15:31:33

+2

爲什麼這是一個「測驗」? – MtnViewMark 2010-03-23 20:12:13

回答

8
  • 如何MapProduct實施?

Prelude> :m + Control.Applicative 
Prelude Control.Applicative> (,,) <$> [1,2,3] <*> ["a","b","c"] <*> [0.8, 1.2, 4.4] 
[(1,"a",0.8),(1,"a",1.2),...,(3,"c",4.4)] 
  • 的功能是什麼的類型?什麼是F的類型?

F的類型取決於您要應用的列表。 <$>這裏是fmap(<*>) :: f(a->b) -> f a -> f b其中f = []在這裏。

  • 你可以處理非均勻列表作爲輸入嗎? (例如,1和「a」的輸入列表中的一個)

有沒有這樣的事,作爲一個異構列表。但你可以simulate a heterogeneous list for a specific context with existential types。然後你可以使用上面的方法來做MapProduct。

*Main Control.Applicative> :i SB 
data ShowBox where 
    SB :: forall s. (Show s) => s -> ShowBox 
    -- Defined at v.hs:1:35-36 
*Main Control.Applicative> [SB 2, SB "a", SB 6.4] 
[2,"a",6.4] 
*Main Control.Applicative> (,) <$> [SB 2, SB "a", SB 6.4] <*> [SB 'z', SB 44] 
[(2,'z'),(2,44),("a",'z'),("a",44),(6.4,'z'),(6.4,44)] 
1

您描述的函數與zipWithN函數密切相關。它將具有相同的類型 - 它只會產生更大的結果列表。現在問題在於沒有辦法在haskell的類型系統中(無擴展名)表達「在t_1, ..., t_n類型中使用N個參數的函數」或「n個類型爲[t_1],...,[t_n]」的列表(或「類型爲([t_1], ..., [t_n]")的n元組」) 。像模板哈斯克爾)這就是爲什麼沒有一個zipWith功能,但一個是支持的參數列表中的每個數字

因此,要回答你的問題:

  • 它通過定義來實現函數mapProductN爲你想要支持的每個數字N,對於N = 2,它看起來像這樣:

    mapProduct f l1 l2 = [f x1 x2 | x1 <- l1, x2 <- x2] 
    

    或作爲一般藍圖(即僞代碼)如何定義的功能的任何N:

    mapProduct f l1 ... ln = [f x1 ... xn | x1 <- l1, ..., xn <- ln] 
    
  • 正如我說的相同類型的zipWith功能,即:

    zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] 
    zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d] 
    zipWith4 :: (a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e] 
    

    因爲f是第一個參數到函數中,第一個參數的類型是f的類型(所以對於n = 2,它將是a -> b -> c

  • 那麼,因爲它具有與zipWith和zipWith類型相同的其他功能,那就是沒有。

  • 如果沒有擴展名,Haskell不允許使用不同類的列表。

  • 除非您願意花時間寫無窮版本的mapProduct,否則列表數量有上限。

+0

總結一下:你的解決方案除了不處理異構輸入列表和可變數量的參數外,其他所有的要求都是一樣的,對不對? – levy 2010-03-23 15:40:41

+0

@levy:對。或者,如果啓用存在類型並使用它們創建異構列表,則此功能對於這些列表(如果您還提供存在類型的函數f)就可以正常工作。 – sepp2k 2010-03-23 15:54:15

+0

這不是真的:「現在的問題是,沒有辦法表達'一個函數,需要N個參數...在haskell的類型系統中(沒有像模板haskell這樣的擴展)。「Oleg在他的網頁上爲Haskell '98提供了一個var-args函數的解決方案。 – porges 2010-03-25 19:51:21

2

可以定義一個函數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"] 

這種方法的缺點是你很可能不得不鍵入註釋結果(如上面的例子所示)。這將是更地道簡單地使用fmapap直接:

> :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模塊可以很容易地概括了所有的單子也是如此。我沒有以使其清楚地解決原來的問題。)