2017-10-29 51 views
1

リストの各要素に別のリストの対応する要素を乗算する関数を実装するにはどうすればよいですか?たとえば、リスト[1, 2, 3][4, 5, 6]が返された場合、[4, 10, 18]が返されますか?私のコードは以下の通りです:Haskellでの掛け算リスト

calcArea :: [Int] -> [Int] -> [Int] 
calcArea length width = length * width 

答えて

8

これはzipWithのための古典的なユースケースである:

calcArea = zipWith (*) 

か、理解することは簡単かもしれたが、等価です:

calcArea length width = zipWith (*) length width 
6

@ForceBruすでに完全に良い答えを書いていますが、この種の関数を自分で書く方法を探究したいと思います。

まず、型シグネチャを書き込むことができます。

calcArea []  []  = -- TODO: case 1 
calcArea (a:as) []  = -- TODO: case 2 
calcArea []  (b:bs) = -- TODO: case 3 
calcArea (a:as) (b:bs) = -- TODO: case 4 

最初のケースは簡単です:

calcArea [] [] = [] 

しかし、今、我々は2つの引数が取ることができる4種類のケースを書き出すことができるように

calcArea :: [Int] -> [Int] -> [Int] 

:あなたはすでにことを持っています2番目と3番目は難しいです。ここでは、リストを切り捨てることを決定しますので、calcArea [1,2,3] [] = []です。また、これは同じサイズのリストで使用されることを意図しています。これが関数の振る舞いではない場合は、これを変更することができます。 (これはzipWithの振る舞いであることに注意してください)また、リストの要素を参照しないので、(a:as)(b:bs)の代わりに_を書くことができます。

calcArea _ [] = [] 
calcArea [] _ = [] 

(これらの例は、最初と重なって、私たちは完全に最初のケースを取り外すことができることにも注意)

最後に、我々はいくつかのリスト内a * bをしたい明らかにケース4を持って、それでは始めましょうそれに:この時点で

calcArea (a:as) (b:bs) = (a * b) : --??? 

、我々はcalcArea as bsが、その後asbs、リストの残りのcalcAreaの最初の2つの要素の積であることを実感します!すなわち、calcArea [1,2,3] [4,5,6] = (1 * 4) : calcArea [2,3] [5,6]です。だから我々は再発することができます:

calcArea (a:as) (b:bs) = (a * b) : calcArea as bs 

ので、完全な機能は次のとおりです。これは私は、これはあなたがHaskellで、より複雑な関数を記述するのに役立ちます願っていますcalcArea = zipWith (*)

と同等であることを

calcArea :: [Int] -> [Int] -> [Int] 
calcArea [] _ = [] 
calcArea _ [] = [] 
calcArea (a:as) (b:bs) = (a * b) : calcArea as bs 

注意未来。

+1

あなたは「商品」を意味し、「合計」は意味しません。私たちがcalcArea [1,2,3] [4,5,6] =(1 * 4)から行くときに、この説明的な(帰納的な)プログラミングが好きです:calcArea [2,3] [ CalcArea(one:two_three)(four:five_six)=(one * four):calcArea two_three five_six'に変換します。 –

+1

そのタイプミスを変更しました。 – AJFarmar

4

@ ForceBruの答えは、この仕事を行う最も簡単な方法です。しかし、コンビナトリアルではなく、「1対1」のオペレーションが必要なときに、リスト上のファンクタとアプリケーション操作を行うためには、より複雑な仕事が必要になることがあります。ですから、この仕事のためだけに考えているのはControl.Applicative.ZipListなので、それは便利かもしれません。

import Control.Applicative 

mult121 :: Num a => [a] -> [a] -> [a] 
mult121 xs ys = getZipList $ (*) <$> ZipList xs <*> ZipList ys 

*Main> mult121 [1,2,3] [4,5,6] 
[4,10,18] 
+1

好奇心のため、 "fmap getZipList"と書くこともできます。 liftA2(*) 'on'ZipList''です。このケースではあまり明確ではないが、 'calcArea = zipWith(*)'のように、ポイントフリーのソリューションがより良くなっているかどうかをチェックする価値があることがよくあります。 –