Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

関数型プログラミングと型システムのメンタルモデル

Naoya Ito
October 26, 2023

 関数型プログラミングと型システムのメンタルモデル

Qiita Conference 2023 Autumun での発表資料です

発表時間の見積もりが下手で後半全然説明できませんでした、すみません!

実際のプロダクト開発ではどうすればいいのか? というケースは以下のスライドを参照してください。
(本スライドは、こちらのプロダクト開発の経験をベースに基礎を再整理したものになります)
https://speakerdeck.com/naoya/typescript-niyoru-graphql-batukuendokai-fa-75b3dab7-90a8-4169-a4dc-d1e7410b9dbd

Naoya Ito

October 26, 2023
Tweet

More Decks by Naoya Ito

Other Decks in Programming

Transcript

  1. ͳͥ͜ͷ࿩ • ࡢࠓͷϓϩάϥϛϯάݴޠʹ͓͚ΔʮܕʯΛͲ͏ଊ͑Δ͔ – ͔͍͘͏ࢲ΋ɺ೥୅ࠒ͸ʮܕ෇͚ΊΜͲ͍͘͞ͳʔʯͱࢥ͍ͬͯͨ – ࠷ۙ͸ɺ౰࣌ͱ͸શ͘ҟͳΔϝϯλϧϞσϧΛ͍࣋ͬͯΔ • ϓϩάϥϛϯάݴޠɺϑϨʔϜϫʔΫʹ͓͚Δؔ਺ܕϓϩάϥϛϯά͔ΒͷӨڹ •

    )BTLFMMΛझຯͰॻ͘Α͏ʹͳͬͯɺϝϯλϧϞσϧ͕ߋ৽͞Εͨ – ੩తܕ෇͚ɺܕਪ࿦ɺؔ਺ܕϓϩάϥϛϯάɺจ຺ܭࢉʜ – ͳ͓ࠓ೔ͷ࿩͸ )BTLFMMಛ༗ͷ࿩Ͱ͸͋Γ·ͤΜɻͦͷͨΊओʹ 5ZQF4DSJQUͷྫ΋ަ͑ͯ࿩͠·͢
  2. ҉໧తͳঢ়ଶมԽ͕ݮΓɺϓϨθϯςʔγϣϯΛએݴతʹهड़Ͱ͖ΔΑ͏ʹͳͬͨ import { useState } from 'react'; export default function

    MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update together</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); +BWB4DSJQU
  3. update : Msg -> Model -> ( Model, Cmd Msg

    ) update msg model = case msg of ToggleLike -> ( { model | photo = Maybe.map toggleLike model.photo }, Cmd.none ) UpdateComment comment -> ( { model | photo = Maybe.map (updateComment comment) model.photo }, Cmd.none ) SaveComment -> ( { model | photo = Maybe.map saveNewComment model.photo }, Cmd.none ) LoadFeed (Ok photo) -> ( { model | photo = Just photo }, Cmd.none ) LoadFeed (Err _) -> ( model, Cmd.none ) viewLikeButton : Photo -> Html Msg viewLikeButton model = let buttonClass = if model.liked then ... div [ class "like-button" ] [ i [ class "fa fa-2x", class buttonClass, onClick ToggleLike ] [] ] &MN 7JFX͸ .PEFMΛඳըɻ Ϣʔβʔૢ࡞ʹԠͯ͡Πϕ ϯτΛૹΔͱŋŋŋ &MNϥϯλΠϜ͕ VQEBUFؔ਺ ΛݺͿɻؔ਺ʹ͸ΠϕϯτʹԠ ͨ͡Ϟσϧͷঢ়ଶભҠΛؔ਺Ͱ هड़͢Δ &MN
  4. 𝑠 = 1 + 2 + 3 + … +

    n • Ͳ͏ॻ͘  ࠷ۙݟ͔͚ͨ – GPSจ खଓతɺ໋ྩܕ – ౳ࠩ਺ྻͷެࣜ – ࠶ؼɺ৞ΈࠐΈ એݴతɺؔ਺ܕ
  5. GPSจͰॻ͘ • ஝͑ΒΕ͍ͯΔ஋Λॻ͖׵͑Δ͜ͱΛ܁Γฦͯ͠ɺͦͷ஋͔Β݁ՌΛಘΔ • ݱࡏͷίϯϐϡʔλɾΞʔΩςΫνϟͷܭࢉϞσϧʹ͍ۙ – ϝϞϦ͔ΒϨδελʹσʔλΛϩʔυ͠ɺԋࢉΛ࣮ߦͯ͠ɺϝϞϦʹॻ͖ग़͢ int total =

    0; for (int i = 1; i <= n; i++) { total += i; } ͱ͜ΖͰɺզʑ͸ίϯϐϡʔλΛ࢖ͬͯܭࢉΛ͍ͯ͠Δ͕ɺϓϩάϥϛϯά্ͷܭࢉϞσϧ·ͰͦΕʹ฿͏ ͜ͱ͸ඞਢͳͷ͔ 
  6. Ҿ਺ʹؔ਺Λద༻͢Δ͜ͱΛ࠶ؼ ؔ਺ݺͼग़͠ Ͱ܁Γฦ͠ɺ஋ΛಘΔ sum [] = 0 sum (x :

    xs) = x + sum xs -- 関数 sum を再帰的に呼び (+) 関数を適用 )BTLFMM const sum = (ns: number[]): number => { if (ns.length == 0) return 0 const [x, ...xs] = ns return x + sum(xs) } 5ZQF4DSJQU
  7. ஋Λॻ͖׵͑ΔͷͰ͸ͳ͘ɺؔ਺ͷ໭Γ஋ʹؔ਺Λ࠶ؼతʹద༻ͯ͠஋ΛಘΔ f a b = a + b main =

    do print $ f 10 (f 9 (f 8 (f 7 (f 6 (f 5 (f 4 (f 3 (f 1 2)))))))) )BTLFMM
  8. ʮ໭Γ஋ʹ܁Γฦؔ͠਺Λద༻͢ΔʯΛؔ਺ʹͨ͠ͷ͕ GPME΍ SFEVDF • ؔ਺Λద༻͢Δ͜ͱͰ஋ΛಘΔ͜ͱʹΑͬͯܭࢉΛ੒͢ͷ͕ɺؔ਺ܕϓϩάϥϛϯάͷߟ͑ํ • ࠜఈʹ͸ϥϜμܭࢉ uuuࠓ೔͸ͦͷ࿩͸͠ͳ͍ let s

    = foldl (+) 0 [1 .. n] )BTLFMM let s = [1, 2, 3, 4, 5].reduce((acc, i) => acc + i, 0)``` let s = [1, 2, 3, 4, 5].reduce((acc, i) => acc + i, 0) 5ZQF4DSJQU
  9. จɺࣜ • จ 4UBUFNFOU – GPSจɺ JGจɺQSJOUจ  – ܭࢉػ΁ͷԿ͔͠Βͷಈ࡞໋ྩɺखଓ͖ɻ஋Λฦ͞ͳ͍

    • ࣜ &YQSFTTJPO – ʮܭࢉΛ࣮ߦͯ݁͠ՌΛಘΔΑ͏ͳॲཧΛهड़͢ΔͨΊͷจ๏ཁૉʯ 8JLJQFEJB – ඞͣ஋Λฦ͢ – ؔ਺ܕϓϩάϥϛϯάʹ͓͚Δؔ਺͸ࣜ
  10. ࠶ܝ GPSจͰॻ͘ int total = 0; for (int i =

    1; i <= n; i++) { total += i; } • GPSจͱ୅ೖจͰɺ܁Γฦ͠ԋࢉ݁ՌΛॻ͖ࠐΉ ୅ೖ͢Δ ໋ྩΛߦ͍ͬͯΔ • ܭࢉػ΁ͷ໋ྩ uuu໋ྩܕ • จͰܭࢉΛߏ੒͢Δͱɺ໋ྩతʹͳΔ
  11. ࠶ܝ ࠶ؼతʹؔ਺Λద༻͢Δ • ࣜʹΑΓܭࢉΛએݴ͢Δ • ࣜ͸ඞͣ஋Λ໭͢ɻͦͷ஋ʹ࠶ͼؔ਺Λద༻͢Δ • ࣜͰܭࢉΛߏ੒͢ΔͱɺએݴతʹͳΔ let s

    = foldl (+) 0 [1 .. n] )BTLFMM let s = [1, 2, 3, 4, 5].reduce((acc, i) => acc + i, 0)``` let s = [1, 2, 3, 4, 5].reduce((acc, i) => acc + i, 0) 5ZQF4DSJQU
  12. customer.archive() 5ZQF4DSJQU const archived = archiveCustomer(customer) 5ZQF4DSJQU • ໋ྩతʹॻ͘ –

    ΦϒδΣΫτͷ಺෦ঢ়ଶΛॻ͖׵͑Δ໋ྩΛߦ͏͜ͱͰɺঢ়ଶΛมԽͤ͞Δ – ঢ়ଶͷมԽ͕҉໧త • ؔ਺తʹॻ͘ – Ҿ਺ͷΦϒδΣΫτʹؔ਺Λద༻ͯ͠ɺঢ়ଶભҠޙͷΦϒδΣΫτΛಘΔ – ભҠલͷঢ়ଶ͸ඞͣҾ਺ʹݱΕɺભҠޙͷঢ়ଶ͸໭Γ஋ʹݱΕΔɻঢ়ଶมԽ͕໌ࣔత
  13. 8FCΞϓϦέʔγϣϯͱ *0 • 8FCΞϓϦέʔγϣϯ։ൃͷଟ͘ͷ෦෼͸ɺίϯϐϡʔλ ֎ք ͱͷ΍ΓͱΓ – σʔλϕʔε͔ΒσʔλΛऔಘͯ͠ *0 –

    8FC"1*Λίʔϧͯ͠ *0 – ୺຤ʹग़ྗ͢Δ *0 – *0͸ίϯϐϡʔλ΁ͷ໋ྩͳͷͰɺ໋ྩతʹهड़͢Δͷ͸ࣗવ Ͱ΋ΞϓϦέʔγϣϯ͕େ͖͘ͳͬͯ͘Δͱʜ IO -> ܭࢉ (ۀ຿ϩδοΫɺঢ়ଶભҠ) -> IO ͷਅΜதͷ෦෼͕େ͖͘ɺෳࡶʹͳ͖ͬͯ·ͤΜ͔
  14. update : Msg -> Model -> ( Model, Cmd Msg

    ) update msg model = case msg of ToggleLike -> ( { model | photo = Maybe.map toggleLike model.photo }, Cmd.none ) UpdateComment comment -> ( { model | photo = Maybe.map (updateComment comment) model.photo }, Cmd.none ) SaveComment -> ( { model | photo = Maybe.map saveNewComment model.photo }, Cmd.none ) LoadFeed (Ok photo) -> ( { model | photo = Just photo }, Cmd.none ) LoadFeed (Err _) -> ( model, Cmd.none ) ࠶ܝ &MN &MN
  15. *0ঢ়ଶભҠ *0 model -> model' *0 JOQVUMPBE *0 PVUQVU *0ͱ੾Γ཭ͤ͹ɺ͜͜Λίϯϐϡʔλ

    ΁ͷ໋ྩͰ͸ͳ͘ɺʮܭࢉʯͱͯ͠એ ݴ͢Δ͜ͱ΋Ͱ͖Δɻ͜͜ͷঢ়ଶ؅ཧ Λ͍͍ײ͡ʹͰ͖Ε͹
  16. ΦχΦϯΞʔΩςΫνϟ ͳͲ Ͱಘ͍ͨ͜ͱ • ςελϏϦςΟ͕޲্͢Δ ෦඼ΛೖΕସ͑ՄೳʹͳΔ – ͦΕ͸ͦ͏ɻͰ΋ɺ෭࣍తͳ΋ͷͰ͋ͬͯओ໨తͰ͸ͳ͍ • ۀ຿ϩδοΫΛ

    *0͔Β੾Γ཭͠ɺܭࢉػ΁ͷ໋ྩͰ͸ͳ͘७ਮͳϩδοΫ ܭࢉ ͱͯ͠ߟ ͑ΒΕΔΑ͏ʹ͍ͨ͠ – ৭ʑͳύϥμΠϜΛద༻Ͱ͖ΔՄೳੑ͕ੜ·ΕΔ • ΦϒδΣΫτࢦ޲Ͱ΋ྑ͍͠ɺखଓܕͰ΋ྑ͍͠ɺؔ਺ܕϓϩάϥϛϯάͰ΋ྑ͍ • ͏ͪɺએݴతʹঢ়ଶ؅ཧ͢Δͷ͸ɺ ݱ࣌఺Ͱ͸ ྑ͍ϓϥΫςΟεͰ͸ͳ͍͔ ˡ ࠓ͜͜
  17. ୤ઢ จΛ࢖͏ͱ͔ͦ͜ΒҶͮΔࣜతʹ໋ྩܕʹͳΔ • )BTLFMMͷ forM_ ࣜ ··· for จΈ͍ͨͳ΋ͷ (※࣮ࡍ͸จͰ͸ͳ͘ϢχοτܕΛฦࣜ͢)

    – ϛϡʔλϒϧͳ഑ྻΛॻ͖׵͑ͨΓɺܭࢉػͱೖग़ྗ͢Δͱ͖ʹ࢖͏ – ܭࢉػ΁ͷ໋ྩతͳࣜͳͷͰ໭Γ஋͕ͳ͍ – ͳ͓ )BTLFMM͔ͩΒͱ໋͍ͬͯྩతʹॻ͚ͳ͍Θ͚Ͱ͸ͳ͍͠ɺ໋ྩతʹهड़͢Δํ͕ྑ͍৔߹΋Α͋͘Δ main = do arr <- newListArray @IOArray (1, 10) [1 .. 10] forM_ [1 .. 10] $ ¥i -> do x <- readArray arr i writeArray arr i (x * 2) forM_ [1 .. 10] $ ¥i -> do readArray arr i >>= print )BTLFMM
  18. ಉ͡໨తͷσʔλߏ଄ͷΠϛϡʔλϒϧ൛ɺϛϡʔλϒϧ൛Λ࢖͏ൺֱ main = do [n, m] <- getInts uvs <-

    replicateM m getTuple let uf0 = newUF (0, n - 1) -- 関数 f により uf を次の状態に遷移させる let (_, xs) = mapAccumL f uf0 uvs where f uf (u, v) = let same = isSame uf u v in if same then (uf, same) else (unite uf u v, same) … -- 状態の表現にイミュータブルなデータ構造 data UnionFind = UnionFind { parent :: IM.IntMap Int, size :: IM.IntMap Int } deriving (Show) )BTLFMM -- 状態の表現にミュータブルな配列 data UnionFind a v = UnionFind (a v v) (IOUArray v Int) )BTLFMM main = do [n, m] <- getInts uvs <- replicateM m getTuple uf <- newUF @IOUArray (0, n - 1) (-1) forM_ uvs $ ¥(u, v) -> do same <- isSame uf u v -- データ構造 uf に作用を起こして内部状態を変える unless same $ do unite uf u ϛϡʔλϒϧͳσʔλߏ଄Λ࢖͏ͱ஋ Λ໭͞ͳ͍ͷͰɺ੍ޚߏ଄΋ؚΊࣗવ ͱ໋ྩܕͷ࣮૷ʹͳΔ ͪͳΈʹࢲ͸ 6OJPO'JOE͸ͪ͜ΒΛ ৗ༻ͯ͠·͢ ؔ਺ͷ໭Γ஋͕࣍ͷঢ়ଶͷσʔλߏ଄ ͳͷͰɺ໭Γ஋ΛҾ͖ճؔ͢਺ܕతͳ ࣮૷ʹͳΔ
  19. • ʮܕ͸ɺޓ͍ʹؔ࿈͢Δ஋ͷू߹Ͱ͢ʯ ϓϩάϥϛϯά )BTLFMM • ʮܕ UZQF ͋Δ͍͸σʔλܕ EBUBUZQF ͱ͸ɺσʔλ͕ͲͷΑ͏ͳੑ࣭ͷू߹ʹଐ͢Δ

    ͔Λࣔ͢΋ͷͰ͢ʯ ؔ਺ܕϓϩάϥϛϯά࣮ફೖ໳ • ʮ Մೳͳૢ࡞΍ԋࢉͳͲͷମܥͳͲ͕ ڞ௨͍ͯ͠Δ஋ͷू߹͕ܕͰ͋ΓɺͦΕͧΕͷ஋͸ ෳ਺ͷू߹ ܕ ʹଐ͢͜ͱ͕Ͱ͖Δʯ 5ZQF4DSJQUʹ͓͚Δܕͷू߹ੑͱ֊૚ੑ • ʮܕ͸஋΍ॲཧͷຬͨ͢΂͖ੑ࣭Λڧ͘ҙຯ෇͚͢ΔͨΊʹ࢖͏͜ͱ͕Ͱ͖ɺʮϓϩάϥϜ ͷਖ਼͠͞ʯΛอূ͢ΔͨΊͷॏཁͳϑΝΫλʔͰ͢ʯ
  20. export function toColor(value: string): Result<Color, ValidationError> { return /^#[0-9a-f]{3}([0-9a-f]{3})?$/i.test(value) ?

    ok(value as Color) : err(new ValidationError('⾊の値が不正です。#FFFFFF形式で指定してください')) } 5ZQF4DSJQU ܕ͸ߏ଄Խ͢Δ͜ͱ͕Ͱ͖Δ
  21. ୅਺తσʔλܕ • )BTLFMMͳͲͷݴޠͰ͸৽͍͠σʔλߏ଄Λఆٛ͢Δͷʹ୅਺తσʔλܕͰදݱ͢Δ • ܕΛ૊Έ߹ΘͤΔͷʹ࿦ཧੵ "/% ͚ͩͰͳ͘ ࿦ཧ࿨ 03 ͕࢖͑Δ

    data Bool = True | False data Maybe a = Nothing | Just a )BTLFMM )BTLFMM data UnionFind = UnionFind { parent :: IM.IntMap Int, size :: IM.IntMap Int } )BTLFMM
  22. ܕͷ૊Έ߹Θͤʹʮ࿨ 03 ʯ͕࢖͑Δ • ৽͍͠σʔλߏ଄ͷܗΛએݴ͢Δखஈ͸֤ݴޠ༷ʑͰ͋Δ͕ɺ͔ͭͯଟ͘ͷݴޠͰ͸ੵ "/% Ͱ૊Έ߹ ΘͤΔͷ͕ओͳํ๏ͩͬͨ – TUSVDU΍

    DMBTTͳͲϨίʔυܕʹΑΔϓϩύςΟͷ૊Έ߹Θͤ͸ "/% • "/%͚ͩͰܕͱܕΛ૊Έ߹ΘͤΔͱɺෆࣗવͳ֊૚΍ෆඞཁͳ஋ͷ૊Έ߹Θ͕ͤൃੜ͠΍͍͢ – ௚ੵͷ֊૚ߏ଄ uuuྫ͑͹ DMBTTʹΑΔ֊૚ߏ଄ data Bool = True | False )BTLFMM
  23. export interface ReservationHolder { kind: 'ReservationHolder' name: string nameKana: string

    | null phoneNumber: PhoneNumber email: EmailAddress | null } export interface Visitor { kind: 'Visitor' name: string nameKana: string | null phoneNumber: PhoneNumber } interface HolderAndVisitor { kind: 'HolderAndVisitor' holder: ReservationHolder visitor: Visitor } interface HolderOnly { kind: 'HolderOnly' holder: ReservationHolder } interface VisitorOnly { kind: 'VisitorOnly' visitor: Visitor } export type ReservationGuest = HolderAndVisitor | HolderOnly | VisitorOnly 5ZQF4DSJQU ߏ଄͕ҟͳΔ΋ͷΛʮ·ͨ͸ ࿨ 03 ʯͰ૊Έ߹ΘͤΔ
  24. l.BLJOHJMMFHBMTUBUFTVOSFQSFTFOUBCMFz interface User { memberId: MemberId | undefined guestId: GuestId

    | undefined } interface Member { userId: MemberId } interface Guest { guestId: GuestId } type User = Member | Guest औΓಘΔ஋ͷछྨ਺͸֤ଐੑͷੵʹͳΔ ௚ੵ Y ɾ྆ํ VOEFGJOFE ɾ྆ํͷ஋͕ຒ·Δ ͱ͍͏࢓্༷͋Γಘͳ͍ঢ়ଶ͕ੜ·ΕΔ औΓಘΔछྨ਺͸֤ଐੑͷ࿨ ௚࿨   ࢓্༷͋Γಘͳ͍ঢ়ଶ͸දݱ͠ͳ͍ ˠ ͦͯ͠ίϯύΠϥ͕ͦΕΛཧղ͢Δ Ϩίʔυ͸ʮ͔ͭ "/% ʯ ϢχΦϯ͸ʮ·ͨ͸ 03 ʯ 5ZQF4DSJQU 5ZQF4DSJQU
  25. type connection_state = | Connecting | Connected | Disconnected type

    connection_info = { state: connection_state; server: inet_addr; last_ping_time: time option; last_ping_id: int option; session_id: string option; when_initiated: time option; when_disconnected: time option; } type connecting = { when_initiated: time; } type connected = { last_ping : (time * int) option; session_id: string; } type disconnected = { when_disconnected: time; } type connection_state = | Connecting of connecting | Connected of connected | Disconnected of disconnected type connection_info = { state: connection_state; server: inet_addr; } 「なぜ次に学ぶ言語は関数型であるべきか - YAMAGUCHI::weblog」 より引用 https://ymotongpoo.hatenablog.com/entry/20111105/1320506449 0$BNM 0$BNM
  26. ͪ͜ΒΑΓ΋ŋŋŋ export class Tag { state: 'Unvalidated' | 'Validated' |

    'Created', id: TagId | undefined, groupId: RestaurantGroupId, label: string, icon: TagIcon | undefined, sortOrder: number | undefined, builtin: boolean | undefined } 5ZQF4DSJQU
  27. interface UnvalidatedTag { kind: 'Unvalidated' groupId: string label: string icon?:

    { symbol: string; type: TagIconType; color?: string | null | undefined } | null | undefined } interface ValidatedTag { kind: 'Validated' groupId: RestaurantGroupId label: string icon: TagIcon } export interface CreatedTag { kind: 'Created' id: TagId groupId: RestaurantGroupId label: TagLabel icon: TagIcon sortOrder: number builtin: boolean } export type Tag = UnvalidatedTag | ValidatedTag | CreatedTag ͪ͜Βͷํ͕ɺ஋ͷ૊Έ߹Θͤύλʔϯ͕গͳ͘ݫີ 5ZQF4DSJQU
  28. ࿨Ͱ૊Έ߹Θͤͯߏஙͨ͠΋ͷ͸ɺύλʔϯϚονͰ෼ղ main = do let someValue :: Maybe String someValue

    = ... case someValue of Just s -> putStrLn (s ++ ", naoya") Nothing -> putStrLn "Farewell" data Maybe a = Nothing | Just a )BTLFMM )BTLFMM +VTU4USJOH͔ /PUIJOHͷͲͪΒ͔ .BZCFܕΛύλʔϯϚονͰ෼ղ͢Δ
  29. 5ZQF4DSJQUͰ΋͍͚·͢ interface Empty { kind: "Empty" } interface Cons<T> {

    kind: "Cons" head: T tail: List<T> } export type List<T> = Empty | Cons<T> data List a = Empty | Cons a (List a) 5ZQF4DSJQU )BTLFMM ϦςϥϧܕͰλάΛ͚͓ͭͯ͘ ϢχΦϯͰ૊Έ߹Θͤͨܕ
  30. // List<T> への map 関数を実装 type map = <T, U>(f:

    (a: T) => U, xs: List<T>) => List<U> export const map: map = (f, xs) => { switch (xs.kind) { case "Empty": return Empty() case "Cons": return Cons(f(xs.head), map(f, xs.tail)) default: assertNever(xs) } } export function assertNever(_: never): never { throw new Error() } console.log(map(i => i * 2, myList)) 5ZQF4DSJQU λάʹԠͯ͡෼ղ ϦςϥϧܕͳͷͰͪΌΜͱܕ͕ޮ͘
  31. ྫ͑͹ಈతܭը๏ φοϓβοΫ໰୊ ͷ࣮૷ for (int j = 0; j <=

    W; ++j) dp[0][j] = 0; for (int i = 0; i < N; ++i) { for (int j = 0; j <= W; ++j) { if (j >= w[i]) dp[i+1][j] = max(dp[i][j-w[i]] + v[i], dp[i][j]); else dp[i+1][j] = dp[i][j]; } } cout << dp[N][W] << endl; let f (w, v) (wi, vi) | v == minBound = [(w, v)] | otherwise = [(w, v), (w + wi, v + vi)] let dp = accumArrayDP @UArray f max minBound (0, wx) [(0, 0)] wvs print $ maximum (elems dp) )BTLFMM $ ू߹ʹԋࢉͭͱ୯ҐݩΛೖΕΕ͹ %1ʹͳΔΑ͏ந৅Խ͍ͯ͠ Δ %1͸൒؀
  32. • ΞϧΰϦζϜΛ୅਺తߏ଄Λҙࣝͯ͠ந৅Խ͢Δɻʮ͜ͷΞϧΰϦζϜ ܭࢉߏ଄ ʹͲΜͳ݁߹ԋࢉΛೖ Εͯ࢖͏͔ʯͱ͍͏ΠϯλϑΣʔεͷؔ਺͕ಘΒΕΔ • ͲΜͳԋࢉΛೖΕΒΕΔ͔ uuuܕ͕อূ͢Δ ೖΕΒΕΔԋࢉͷू߹Λఆٛ͢Δ let

    sections = shakutori (1, n) (s !) (+) (-) 0 (¥acc r -> acc + r <= k) let s = scanl' (+) 0 xs let dp = doubling f (+) (10 ^ 5, 10 ^ 18) xs ͠Ό͘ͱΓ๏ μϒϦϯά ྦྷੵԋࢉ
  33. ࠶ܝ ਤ͸ԿΛݴ͍ͬͯΔ͔ • ϓϩάϥϜΛʮܭࢉػ΁ͷ໋ྩʯͰ͸ͳ͘ʮؔ਺Λద༻ͯ͠஋ΛಘΔܭࢉʯͷఆٛͱଊ͑Δ • ؔ਺ G͸ɺ஋Λࣸ͢΋ͷ • ͲΜͳू߹͔ΒͲΜͳू߹ʹࣸ͞ΕΔ͔ɻͦͷू߹ΛܕͰදݱ͢Δ •

    ू߹ͷදݱɺͭ·ΓʮܕͱܕΛ૊Έ߹Θͤͨߏ଄Խʯ͕ΑΓྑ͘Ͱ͖Ε͹ɺϓϩάϥϜ͕ݎ࿚ʹͳΔ ࠷ۙ͸͜ͷߟ͑Λத৺ʹஔ͍ͯɺϓϩάϥϜઃܭΛ͍ͯ͠·͢ ʮू߹Ͱ͋ΔܕͰઃܭ͠ɺؔ਺Ͱঢ়ଶΛભҠʯ
  34. ͲΜͳϓϩάϥϛϯάݴޠͰ΋ؔ਺ܕͰΨϯΨϯ΍͍ͬͯ͘΂͖ • ๯಄ʹ΋ड़΂ͨ௨Γɺؔ਺ܕϓϩάϥϛϯά࠷ڧɺͱ͍͏࿩͸͍ͯ͠·ͤΜ • Αͬͯɺࢲݟ͸ʮ͍͍͑ʯݴޠͷಛੑʹ߹Θͤ·͠ΐ͏ – )BTLFMMɺ 'ɺ 0$BNMɺ4DBMBͳͲͦ͏͢Δ͜ͱΛલఏʹ࡞ΒΕ͍ͯΔݴޠ͸໰୊ͳ͍Ͱ͠ΐ͏ –

    5ZQF4DSJQUuuuؔ਺ܕͱͯ͠ͷଆ໘͸͋Γ·͕͢ɺγϯλοΫε໘Ͱ͸લஈͷݴޠʹൺֱ͢Δͱෆ଍΋ײ͡·͢ɻ Ұํ 54ͷܕγεςϜ͸ɺ͝ଘ஌ͷ௨Γಈతͳಛ௃΋͋ΓɺඇৗʹڧྗͰ͢ɻܕ͸ू߹ͷϝϯλϧϞσϧͰ্ख ʹ࢖͍ɺؔ਺ܕͷΤοηϯεΛऔΓೖΕͭͭ΋ɺ໋ྩతʹॻ͚͹͍͍৔໘Ͱ͸ແཧΛ͠ͳ͍uuu͙Β͍͕ྑ͍όϥ ϯεͰ͸ͳ͍Ͱ͠ΐ͏͔ • ࢲ͸ 3FTVMUܕΛ࢖ͬͯؔ਺ܕدΓͰ΍͍ͬͯ·͕͢ɺ͍͍ଆ໘΋͋Γ·͕͢໘౗ͳ͜ͱ΋͋Γ·͢ – 3VTUɺ,PUMJOɺ4XJGUuuuܕʹʮ03ʯ૬౰ͷػೳ͕͋ΓɺܕγεςϜ͸ݱ୅తͰ͢ɻͲΜͳελΠϧ͕͍͍͔͸ɺ ৄ͘͠ͳ͍ͷͰΘ͔Γ·ͤΜɻ֤ݴޠͳΓͷʮ˓˓ 8BZʯ͕͋Δͱࢥ͍·͢ɺࣝऀʹ͓ฉ͖͍ͩ͘͞
  35. ࢀߟจݙ • 8JMM,VSUஶ גࣜձࣾΫΠʔϓ ༁ ʮೖ໳ )BTLFMMϓϩάϥϛϯάʯ ᠳӭࣾ  •

    (SBIBN)VUUPOஶ ࢁຊ࿨඙ ༁ ʮϓϩάϥϛϯά )BTLFMMୈ൛ʯ ϥϜμϊʔτ  • 4DPUU8MBTDIJOஶ ʮ%PNBJO.PEFMJOH.BEF'VODUJPOBMʯ  • +FSFNZ'BJSCBOL ஶ ϠΪͷ͘͞ΒͪΌΜ ຋༁ ʮϓϩάϥϛϯά&MNᴷ҆શͰϝϯςφϯε͠΍ ͍͢ϑϩϯτΤϯυΞϓϦέʔγϣϯ։ൃೖ໳ʯ ϚΠφϏग़൛  • େ઒ಙ೭ஶ ʮ<૿ิվగ>ؔ਺ϓϩάϥϛϯά࣮ફೖ໳ʯ ٕज़ධ࿦ࣾ  • 8FCͷϦιʔε – 5ZQF4DSJQUʹ͓͚Δܕͷू߹ੑͱ֊૚ੑ IUUQT[FOOEFWFTUSBBSUJDMFTUZQFTDSJQUUZQFTFUIJFSBSDIZ – ʮͳͥ࣍ʹֶͿݴޠ͸ؔ਺ܕͰ͋Δ΂͖͔  :"."(6$)*XFCMPHʯ  IUUQTZNPUPOHQPPIBUFOBCMPHDPNFOUSZ