Haskell
addm::[Int]->Int
addm (x:xs) = sum(x:xs)
sum関数を使用してリストの合計を取得することはできましたが、関数を使用してリストの合計を取得することはできmapますか?また、マップ機能の用途は何ですか?
mapmapは各リスト要素を他の要素から独立して扱うため、実際にリストを合計するために使用することはできません。mapたとえば、次のようにリスト内の各値をインクリメントするために使用できます。
map (+1) [1,2,3,4] -- gives [2,3,4,5]
addmを実装する別の方法は、foldlを使用することです。
addm' = foldl (+) 0
これが、おそらく不可能な定義sumですmap。
sum' xs = let { ys = 0 : map (\(a,b) -> a + b) (zip xs ys) } in last ys
これは実際に(とと)scanlの観点からどのように実装できるかを示しています。上記は:と同等です。map ziplastfoldl (+) 0 xs === last $ scanl (+) 0 xs
scanl' f z xs = let { ys = z : map (uncurry f) (zip ys xs) } in ys
を使って多くのことを計算できmap、あらゆる種類の情報が流れるように調整できると思いzipます。
編集:上記は zipWithもちろん変装です(そしてzipWith一種のmap2):
sum' xs = let { ys = 0 : zipWith (+) ys xs } in last ys
scanlこれは、がよりも用途が広いことを示唆しているようですfoldl。
mapリストをその合計に減らすために使用することはできません。その再帰パターンはfoldです。
sum :: [Int] -> Int
sum = foldr (+) 0
余談ですがmap、フォールドとして定義することもできることに注意してください。
map :: (a -> b) -> ([a] -> [b])
map f = fold (\x xs -> f x : xs) []
これは、foldrがリストの正規再帰関数であるためです。
参考文献:褶曲の普遍性と表現力に関するチュートリアル、Graham Hutton、J。Functional Programming 9(4):355–372、1999年7月。
いくつかの洞察の後、私は別の答えを追加する必要があります:でリストの合計を取得することはできませんが、mapそのモナディックバージョンで合計を取得することはできますmapM。あなたがする必要があるのは、モノイド(LYAHFGGを参照)の上にWriterモナド(LYAHFGGを参照)を使用することです。Sum
私は特別なバージョンを書きましたが、それはおそらく理解しやすいでしょう:
data Adder a = Adder a Int
instance Monad Adder where
return x = Adder x 0
(Adder x s) >>= f = let Adder x' s' = f x
in Adder x' (s + s')
toAdder x = Adder x x
sum' xs = let Adder _ s = mapM toAdder xs in s
main = print $ sum' [1..100]
--5050
Adderあるタイプの単なるラッパーであり、「ランニングサム」も保持します。Adderモナドを作成できます。ここでいくつかの作業を行います。操作>>=(別名「バインド」)が実行されると、新しい結果と、その結果の現在の合計の値に元の現在の合計を加えた値が返されます。このtoAdder関数はIntを受け取り、Adderその引数をラップされた値と実行中の合計の両方として保持するを作成します(実際には、値には関心がなく、合計部分のみに関心があります)。次に、insum' mapMはその魔法を実行できます。mapモナドに埋め込まれた値の場合と同様に機能しますが、のような「モナド」関数を実行し、これらの呼び出しtoAdderをチェーンします(sequenceこれをする)。この時点で、モナドの「バックドア」を通過して、標準mapが欠落しているリスト要素間の相互作用を取得します。
リストの各要素を出力の要素に「マップ」します。
let f(x) = x*x
map f [1,2,3]
これにより、正方形のリストが返されます。
リスト内のすべての要素を合計するには、foldを使用します。
foldl (+) 0 [1,2,3]
+は適用する関数、0は初期値(合計は0、製品は1など)
他の回答が指摘しているように、「通常の」方法はfold関数の1つを使用することです。whileただし、命令型言語でループに非常によく似たものを書くことは可能です。
sum' [] = 0
sum' xs = head $ until single loop xs where
single [_] = True
single _ = False
loop (x1 : x2 : xs) = (x1 + x2) : xs
リストの最初の2つの要素を、1つの要素のリストになるまで追加し、その値を返します(を使用してhead)。
この質問は答えられたと思いますが、私はこの考えを追加したいと思いました...
listLen2 :: [a] -> Int
listLen2 = sum . map (const 1)
リスト内の各項目に対して定数1を返し、合計を返すと思います。コーディングのベストプラクティスではないかもしれませんが、それは私の教授が私たちに学生に与えた例であり、この質問によく関係しているようです。
mapドライバーが映画を見るための主要なツールになることは決してないのとほぼ同じように、コンテナの要素を合計するための主要なツールになることは決してありません。ただし、ドライバーを使用して映写機を固定することはできます。あなたが本当に望むなら、あなたは書くことができます
import Data.Monoid
import Data.Foldable
mySum :: (Foldable f, Functor f, Num a)
=> f a -> a
mySum = getSum . fold . fmap Sum
もちろん、これはばかげています。より一般的で、おそらくより効率的なバージョンを入手できます。
mySum' :: (Foldable f, Num a) => f a -> a
mySum' = getSum . foldMap Sum
またはsum、実際に仕事のために作られたので、を使用することをお勧めします。