bz2-1.0.0.1/0000755000000000000000000000000007346545000010535 5ustar0000000000000000bz2-1.0.0.1/CHANGELOG.md0000644000000000000000000000066507346545000012355 0ustar0000000000000000# bz2 ## 1.0.0.0 * Remove `Codec.Compression.BZip.Foreign` * Use `ForeignPtr` under the hood * Lazier streaming; memory use should be sensible ## 0.1.1.2 * Use `ForeignPtr`s under the hood in various places (over `bracket`) ## 0.1.1.1 * Haddock improvements ## 0.1.1.0 * Change type signature of `bZ2BzlibVersion` * Add `Codec.Compression.BZip` module ## 0.1.0.1 * Fix distribution ## 0.1.0.0 Initial release bz2-1.0.0.1/LICENSE0000644000000000000000000000266707346545000011555 0ustar0000000000000000Copyright Vanessa McHale (c) 2020 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bz2-1.0.0.1/Makefile0000755000000000000000000000061207346545000012177 0ustar0000000000000000.PHONY: clean SHELL := bash MAKEFLAGS += --warn-undefined-variables --no-builtin-rules -j .DELETE_ON_ERROR: setup: valgrind-3.15.0.tar clean: rm -rf .stack-work dist-newstyle dist *.tar* *.hp *.prof stack.yaml.lock tags *.svg valgrind-3.15.0.tar.bz2: wget https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 -O $@ valgrind-3.15.0.tar: valgrind-3.15.0.tar.bz2 bzip2 -d $< --keep bz2-1.0.0.1/README.md0000644000000000000000000000103007346545000012006 0ustar0000000000000000# bz2 High-level bindings to [bzip2](https://www.sourceware.org/bzip2/). ## Comparison Compared to [bzlib](http://hackage.haskell.org/package/bzlib): * Bundles `bzip2` 1.0.8. * Compatible with GHC 8.8.2 * Uses [c2hs](https://github.com/haskell/c2hs) rather than [hsc2hs](https://hackage.haskell.org/package/hsc2hs) and thus has a larger dependency footprint ## Backpack Integration `bz2` implements [`bzip-signature`](http://hackage.haskell.org/package/bzip-signature), which makes it interchangeable with `bzlib`. bz2-1.0.0.1/bench/0000755000000000000000000000000007346545000011614 5ustar0000000000000000bz2-1.0.0.1/bench/Bench.hs0000644000000000000000000000300107346545000013161 0ustar0000000000000000module Main (main) where -- TODO: bench bzlib? import qualified Codec.Compression.BZip as BZ2 import Criterion.Main import qualified Data.ByteString.Lazy as BSL import System.FilePath (()) import System.IO.Temp (withSystemTempDirectory) decompressDump :: IO () decompressDump = withSystemTempDirectory "bz2" $ \fp -> BSL.writeFile (fp "valgrind-3.15.0.tar") =<< (BZ2.decompress <$> BSL.readFile "valgrind-3.15.0.tar.bz2") decompressFile :: FilePath -> IO BSL.ByteString decompressFile = fmap BZ2.decompress . BSL.readFile compressFile :: FilePath -> IO BSL.ByteString compressFile = fmap BZ2.compress . BSL.readFile main :: IO () main = defaultMain [ bgroup "decompressDump" [ bench "decompress + write to file" $ nfIO decompressDump ] , bgroup "decompress" [ bench "decompress file" $ nfIO (decompressFile "test/data/sample1.bz2") , bench "decompress file" $ nfIO (decompressFile "test/data/sample2.bz2") , bench "decompress file" $ nfIO (decompressFile "test/data/sample3.bz2") ] , bgroup "compress" [ bench "compress file" $ nfIO (compressFile "test/data/sample1.ref") , bench "compress file" $ nfIO (compressFile "test/data/sample2.ref") , bench "compress file" $ nfIO (compressFile "test/data/sample3.ref") ] ] bz2-1.0.0.1/bz2.cabal0000644000000000000000000000743307346545000012225 0ustar0000000000000000cabal-version: 1.18 name: bz2 version: 1.0.0.1 license: BSD3 license-file: LICENSE copyright: Copyright: (c) 2020 Vanessa McHale maintainer: vamchale@gmail.com author: Vanessa McHale bug-reports: https://hub.darcs.net/vmchale/bz2/issues synopsis: Bindings to libbz2 description: High-level bindings to libbz2 using c2hs and ByteString category: Compression build-type: Simple data-files: test/data/sample1.ref test/data/sample2.ref test/data/sample3.ref test/data/sample1.bz2 test/data/sample2.bz2 test/data/sample3.bz2 extra-source-files: cbits/bzlib_private.h Makefile extra-doc-files: README.md CHANGELOG.md source-repository head type: darcs location: https://hub.darcs.net/vmchale/bz2 flag cross description: Set this flag if cross-compiling default: False manual: True library exposed-modules: Codec.Compression.BZip cc-options: -O3 c-sources: cbits/bzlib.c cbits/randtable.c cbits/crctable.c cbits/compress.c cbits/blocksort.c cbits/huffman.c cbits/decompress.c hs-source-dirs: src other-modules: Codec.Compression.BZip.Foreign.Common Codec.Compression.BZip.Foreign.Compress Codec.Compression.BZip.Foreign.Decompress Codec.Compression.BZip.Common Codec.Compression.BZip.Unpack Codec.Compression.BZip.Pack default-language: Haskell2010 other-extensions: DeriveDataTypeable TupleSections include-dirs: cbits install-includes: cbits/bzlib.h ghc-options: -Wall build-depends: base >=4.4 && <5, bytestring -any if !flag(cross) build-tool-depends: c2hs:c2hs >=0.26.1 if impl(ghc >=8.0) ghc-options: -Wincomplete-uni-patterns -Wincomplete-record-updates -Wredundant-constraints if impl(ghc >=8.4) ghc-options: -Wmissing-export-lists test-suite bz2-test type: exitcode-stdio-1.0 main-is: Spec.hs hs-source-dirs: test default-language: Haskell2010 ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall build-depends: base -any, bz2 -any, bytestring -any, filepath >=1.4.0.0, tasty -any, tasty-golden -any, tasty-hunit -any, deepseq -any, directory -any if impl(ghc >=8.0) ghc-options: -Wincomplete-uni-patterns -Wincomplete-record-updates -Wredundant-constraints -Widentities if impl(ghc >=8.4) ghc-options: -Wmissing-export-lists if impl(ghc >=8.2) ghc-options: -Wcpp-undef benchmark bz2-bench type: exitcode-stdio-1.0 main-is: Bench.hs hs-source-dirs: bench default-language: Haskell2010 ghc-options: -threaded -rtsopts -with-rtsopts=-N -O3 -Wall build-depends: base -any, bz2 -any, criterion -any, filepath -any, temporary -any, bytestring -any if impl(ghc >=8.0) ghc-options: -Wincomplete-uni-patterns -Wincomplete-record-updates -Wredundant-constraints -Widentities if impl(ghc >=8.4) ghc-options: -Wmissing-export-lists if impl(ghc >=8.2) ghc-options: -Wcpp-undef benchmark bz2-mem type: exitcode-stdio-1.0 main-is: Mem.hs hs-source-dirs: mem default-language: Haskell2010 ghc-options: -Wall build-depends: base -any, bz2 -any, filepath -any, temporary -any, bytestring -any if impl(ghc >=8.0) ghc-options: -Wincomplete-uni-patterns -Wincomplete-record-updates bz2-1.0.0.1/cbits/0000755000000000000000000000000007346545000011641 5ustar0000000000000000bz2-1.0.0.1/cbits/blocksort.c0000644000000000000000000007377107346545000014026 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Block sorting machinery ---*/ /*--- blocksort.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #include "bzlib_private.h" /*---------------------------------------------*/ /*--- Fallback O(N log(N)^2) sorting ---*/ /*--- algorithm, for repetitive blocks ---*/ /*---------------------------------------------*/ /*---------------------------------------------*/ static __inline__ void fallbackSimpleSort ( UInt32* fmap, UInt32* eclass, Int32 lo, Int32 hi ) { Int32 i, j, tmp; UInt32 ec_tmp; if (lo == hi) return; if (hi - lo > 3) { for ( i = hi-4; i >= lo; i-- ) { tmp = fmap[i]; ec_tmp = eclass[tmp]; for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) fmap[j-4] = fmap[j]; fmap[j-4] = tmp; } } for ( i = hi-1; i >= lo; i-- ) { tmp = fmap[i]; ec_tmp = eclass[tmp]; for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) fmap[j-1] = fmap[j]; fmap[j-1] = tmp; } } /*---------------------------------------------*/ #define fswap(zz1, zz2) \ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } #define fvswap(zzp1, zzp2, zzn) \ { \ Int32 yyp1 = (zzp1); \ Int32 yyp2 = (zzp2); \ Int32 yyn = (zzn); \ while (yyn > 0) { \ fswap(fmap[yyp1], fmap[yyp2]); \ yyp1++; yyp2++; yyn--; \ } \ } #define fmin(a,b) ((a) < (b)) ? (a) : (b) #define fpush(lz,hz) { stackLo[sp] = lz; \ stackHi[sp] = hz; \ sp++; } #define fpop(lz,hz) { sp--; \ lz = stackLo[sp]; \ hz = stackHi[sp]; } #define FALLBACK_QSORT_SMALL_THRESH 10 #define FALLBACK_QSORT_STACK_SIZE 100 static void fallbackQSort3 ( UInt32* fmap, UInt32* eclass, Int32 loSt, Int32 hiSt ) { Int32 unLo, unHi, ltLo, gtHi, n, m; Int32 sp, lo, hi; UInt32 med, r, r3; Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; r = 0; sp = 0; fpush ( loSt, hiSt ); while (sp > 0) { AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); fpop ( lo, hi ); if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { fallbackSimpleSort ( fmap, eclass, lo, hi ); continue; } /* Random partitioning. Median of 3 sometimes fails to avoid bad cases. Median of 9 seems to help but looks rather expensive. This too seems to work but is cheaper. Guidance for the magic constants 7621 and 32768 is taken from Sedgewick's algorithms book, chapter 35. */ r = ((r * 7621) + 1) % 32768; r3 = r % 3; if (r3 == 0) med = eclass[fmap[lo]]; else if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else med = eclass[fmap[hi]]; unLo = ltLo = lo; unHi = gtHi = hi; while (1) { while (1) { if (unLo > unHi) break; n = (Int32)eclass[fmap[unLo]] - (Int32)med; if (n == 0) { fswap(fmap[unLo], fmap[ltLo]); ltLo++; unLo++; continue; }; if (n > 0) break; unLo++; } while (1) { if (unLo > unHi) break; n = (Int32)eclass[fmap[unHi]] - (Int32)med; if (n == 0) { fswap(fmap[unHi], fmap[gtHi]); gtHi--; unHi--; continue; }; if (n < 0) break; unHi--; } if (unLo > unHi) break; fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; } AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); if (gtHi < ltLo) continue; n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); n = lo + unLo - ltLo - 1; m = hi - (gtHi - unHi) + 1; if (n - lo > hi - m) { fpush ( lo, n ); fpush ( m, hi ); } else { fpush ( m, hi ); fpush ( lo, n ); } } } #undef fmin #undef fpush #undef fpop #undef fswap #undef fvswap #undef FALLBACK_QSORT_SMALL_THRESH #undef FALLBACK_QSORT_STACK_SIZE /*---------------------------------------------*/ /* Pre: nblock > 0 eclass exists for [0 .. nblock-1] ((UChar*)eclass) [0 .. nblock-1] holds block ptr exists for [0 .. nblock-1] Post: ((UChar*)eclass) [0 .. nblock-1] holds block All other areas of eclass destroyed fmap [0 .. nblock-1] holds sorted order bhtab [ 0 .. 2+(nblock/32) ] destroyed */ #define SET_BH(zz) bhtab[(zz) >> 5] |= ((UInt32)1 << ((zz) & 31)) #define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~((UInt32)1 << ((zz) & 31)) #define ISSET_BH(zz) (bhtab[(zz) >> 5] & ((UInt32)1 << ((zz) & 31))) #define WORD_BH(zz) bhtab[(zz) >> 5] #define UNALIGNED_BH(zz) ((zz) & 0x01f) static void fallbackSort ( UInt32* fmap, UInt32* eclass, UInt32* bhtab, Int32 nblock, Int32 verb ) { Int32 ftab[257]; Int32 ftabCopy[256]; Int32 H, i, j, k, l, r, cc, cc1; Int32 nNotDone; Int32 nBhtab; UChar* eclass8 = (UChar*)eclass; /*-- Initial 1-char radix sort to generate initial fmap and initial BH bits. --*/ if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); for (i = 0; i < 257; i++) ftab[i] = 0; for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; for (i = 0; i < nblock; i++) { j = eclass8[i]; k = ftab[j] - 1; ftab[j] = k; fmap[k] = i; } nBhtab = 2 + (nblock / 32); for (i = 0; i < nBhtab; i++) bhtab[i] = 0; for (i = 0; i < 256; i++) SET_BH(ftab[i]); /*-- Inductively refine the buckets. Kind-of an "exponential radix sort" (!), inspired by the Manber-Myers suffix array construction algorithm. --*/ /*-- set sentinel bits for block-end detection --*/ for (i = 0; i < 32; i++) { SET_BH(nblock + 2*i); CLEAR_BH(nblock + 2*i + 1); } /*-- the log(N) loop --*/ H = 1; while (1) { if (verb >= 4) VPrintf1 ( " depth %6d has ", H ); j = 0; for (i = 0; i < nblock; i++) { if (ISSET_BH(i)) j = i; k = fmap[i] - H; if (k < 0) k += nblock; eclass[k] = j; } nNotDone = 0; r = -1; while (1) { /*-- find the next non-singleton bucket --*/ k = r + 1; while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; if (ISSET_BH(k)) { while (WORD_BH(k) == 0xffffffff) k += 32; while (ISSET_BH(k)) k++; } l = k - 1; if (l >= nblock) break; while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; if (!ISSET_BH(k)) { while (WORD_BH(k) == 0x00000000) k += 32; while (!ISSET_BH(k)) k++; } r = k - 1; if (r >= nblock) break; /*-- now [l, r] bracket current bucket --*/ if (r > l) { nNotDone += (r - l + 1); fallbackQSort3 ( fmap, eclass, l, r ); /*-- scan bucket and generate header bits-- */ cc = -1; for (i = l; i <= r; i++) { cc1 = eclass[fmap[i]]; if (cc != cc1) { SET_BH(i); cc = cc1; }; } } } if (verb >= 4) VPrintf1 ( "%6d unresolved strings\n", nNotDone ); H *= 2; if (H > nblock || nNotDone == 0) break; } /*-- Reconstruct the original block in eclass8 [0 .. nblock-1], since the previous phase destroyed it. --*/ if (verb >= 4) VPrintf0 ( " reconstructing block ...\n" ); j = 0; for (i = 0; i < nblock; i++) { while (ftabCopy[j] == 0) j++; ftabCopy[j]--; eclass8[fmap[i]] = (UChar)j; } AssertH ( j < 256, 1005 ); } #undef SET_BH #undef CLEAR_BH #undef ISSET_BH #undef WORD_BH #undef UNALIGNED_BH /*---------------------------------------------*/ /*--- The main, O(N^2 log(N)) sorting ---*/ /*--- algorithm. Faster for "normal" ---*/ /*--- non-repetitive blocks. ---*/ /*---------------------------------------------*/ /*---------------------------------------------*/ static __inline__ Bool mainGtU ( UInt32 i1, UInt32 i2, UChar* block, UInt16* quadrant, UInt32 nblock, Int32* budget ) { Int32 k; UChar c1, c2; UInt16 s1, s2; AssertD ( i1 != i2, "mainGtU" ); /* 1 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 2 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 3 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 4 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 5 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 6 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 7 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 8 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 9 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 10 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 11 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; /* 12 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); i1++; i2++; k = nblock + 8; do { /* 1 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 2 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 3 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 4 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 5 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 6 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 7 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; /* 8 */ c1 = block[i1]; c2 = block[i2]; if (c1 != c2) return (c1 > c2); s1 = quadrant[i1]; s2 = quadrant[i2]; if (s1 != s2) return (s1 > s2); i1++; i2++; if (i1 >= nblock) i1 -= nblock; if (i2 >= nblock) i2 -= nblock; k -= 8; (*budget)--; } while (k >= 0); return False; } /*---------------------------------------------*/ /*-- Knuth's increments seem to work better than Incerpi-Sedgewick here. Possibly because the number of elems to sort is usually small, typically <= 20. --*/ static Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484 }; static void mainSimpleSort ( UInt32* ptr, UChar* block, UInt16* quadrant, Int32 nblock, Int32 lo, Int32 hi, Int32 d, Int32* budget ) { Int32 i, j, h, bigN, hp; UInt32 v; bigN = hi - lo + 1; if (bigN < 2) return; hp = 0; while (incs[hp] < bigN) hp++; hp--; for (; hp >= 0; hp--) { h = incs[hp]; i = lo + h; while (True) { /*-- copy 1 --*/ if (i > hi) break; v = ptr[i]; j = i; while ( mainGtU ( ptr[j-h]+d, v+d, block, quadrant, nblock, budget ) ) { ptr[j] = ptr[j-h]; j = j - h; if (j <= (lo + h - 1)) break; } ptr[j] = v; i++; /*-- copy 2 --*/ if (i > hi) break; v = ptr[i]; j = i; while ( mainGtU ( ptr[j-h]+d, v+d, block, quadrant, nblock, budget ) ) { ptr[j] = ptr[j-h]; j = j - h; if (j <= (lo + h - 1)) break; } ptr[j] = v; i++; /*-- copy 3 --*/ if (i > hi) break; v = ptr[i]; j = i; while ( mainGtU ( ptr[j-h]+d, v+d, block, quadrant, nblock, budget ) ) { ptr[j] = ptr[j-h]; j = j - h; if (j <= (lo + h - 1)) break; } ptr[j] = v; i++; if (*budget < 0) return; } } } /*---------------------------------------------*/ /*-- The following is an implementation of an elegant 3-way quicksort for strings, described in a paper "Fast Algorithms for Sorting and Searching Strings", by Robert Sedgewick and Jon L. Bentley. --*/ #define mswap(zz1, zz2) \ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } #define mvswap(zzp1, zzp2, zzn) \ { \ Int32 yyp1 = (zzp1); \ Int32 yyp2 = (zzp2); \ Int32 yyn = (zzn); \ while (yyn > 0) { \ mswap(ptr[yyp1], ptr[yyp2]); \ yyp1++; yyp2++; yyn--; \ } \ } static __inline__ UChar mmed3 ( UChar a, UChar b, UChar c ) { UChar t; if (a > b) { t = a; a = b; b = t; }; if (b > c) { b = c; if (a > b) b = a; } return b; } #define mmin(a,b) ((a) < (b)) ? (a) : (b) #define mpush(lz,hz,dz) { stackLo[sp] = lz; \ stackHi[sp] = hz; \ stackD [sp] = dz; \ sp++; } #define mpop(lz,hz,dz) { sp--; \ lz = stackLo[sp]; \ hz = stackHi[sp]; \ dz = stackD [sp]; } #define mnextsize(az) (nextHi[az]-nextLo[az]) #define mnextswap(az,bz) \ { Int32 tz; \ tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } #define MAIN_QSORT_SMALL_THRESH 20 #define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) #define MAIN_QSORT_STACK_SIZE 100 static void mainQSort3 ( UInt32* ptr, UChar* block, UInt16* quadrant, Int32 nblock, Int32 loSt, Int32 hiSt, Int32 dSt, Int32* budget ) { Int32 unLo, unHi, ltLo, gtHi, n, m, med; Int32 sp, lo, hi, d; Int32 stackLo[MAIN_QSORT_STACK_SIZE]; Int32 stackHi[MAIN_QSORT_STACK_SIZE]; Int32 stackD [MAIN_QSORT_STACK_SIZE]; Int32 nextLo[3]; Int32 nextHi[3]; Int32 nextD [3]; sp = 0; mpush ( loSt, hiSt, dSt ); while (sp > 0) { AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); mpop ( lo, hi, d ); if (hi - lo < MAIN_QSORT_SMALL_THRESH || d > MAIN_QSORT_DEPTH_THRESH) { mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); if (*budget < 0) return; continue; } med = (Int32) mmed3 ( block[ptr[ lo ]+d], block[ptr[ hi ]+d], block[ptr[ (lo+hi)>>1 ]+d] ); unLo = ltLo = lo; unHi = gtHi = hi; while (True) { while (True) { if (unLo > unHi) break; n = ((Int32)block[ptr[unLo]+d]) - med; if (n == 0) { mswap(ptr[unLo], ptr[ltLo]); ltLo++; unLo++; continue; }; if (n > 0) break; unLo++; } while (True) { if (unLo > unHi) break; n = ((Int32)block[ptr[unHi]+d]) - med; if (n == 0) { mswap(ptr[unHi], ptr[gtHi]); gtHi--; unHi--; continue; }; if (n < 0) break; unHi--; } if (unLo > unHi) break; mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; } AssertD ( unHi == unLo-1, "mainQSort3(2)" ); if (gtHi < ltLo) { mpush(lo, hi, d+1 ); continue; } n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); n = lo + unLo - ltLo - 1; m = hi - (gtHi - unHi) + 1; nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); mpush (nextLo[0], nextHi[0], nextD[0]); mpush (nextLo[1], nextHi[1], nextD[1]); mpush (nextLo[2], nextHi[2], nextD[2]); } } #undef mswap #undef mvswap #undef mpush #undef mpop #undef mmin #undef mnextsize #undef mnextswap #undef MAIN_QSORT_SMALL_THRESH #undef MAIN_QSORT_DEPTH_THRESH #undef MAIN_QSORT_STACK_SIZE /*---------------------------------------------*/ /* Pre: nblock > N_OVERSHOOT block32 exists for [0 .. nblock-1 +N_OVERSHOOT] ((UChar*)block32) [0 .. nblock-1] holds block ptr exists for [0 .. nblock-1] Post: ((UChar*)block32) [0 .. nblock-1] holds block All other areas of block32 destroyed ftab [0 .. 65536 ] destroyed ptr [0 .. nblock-1] holds sorted order if (*budget < 0), sorting was abandoned */ #define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) #define SETMASK (1 << 21) #define CLEARMASK (~(SETMASK)) static void mainSort ( UInt32* ptr, UChar* block, UInt16* quadrant, UInt32* ftab, Int32 nblock, Int32 verb, Int32* budget ) { Int32 i, j, k, ss, sb; Int32 runningOrder[256]; Bool bigDone[256]; Int32 copyStart[256]; Int32 copyEnd [256]; UChar c1; Int32 numQSorted; UInt16 s; if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); /*-- set up the 2-byte frequency table --*/ for (i = 65536; i >= 0; i--) ftab[i] = 0; j = block[0] << 8; i = nblock-1; for (; i >= 3; i -= 4) { quadrant[i] = 0; j = (j >> 8) | ( ((UInt16)block[i]) << 8); ftab[j]++; quadrant[i-1] = 0; j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); ftab[j]++; quadrant[i-2] = 0; j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); ftab[j]++; quadrant[i-3] = 0; j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); ftab[j]++; } for (; i >= 0; i--) { quadrant[i] = 0; j = (j >> 8) | ( ((UInt16)block[i]) << 8); ftab[j]++; } /*-- (emphasises close relationship of block & quadrant) --*/ for (i = 0; i < BZ_N_OVERSHOOT; i++) { block [nblock+i] = block[i]; quadrant[nblock+i] = 0; } if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); /*-- Complete the initial radix sort --*/ for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; s = block[0] << 8; i = nblock-1; for (; i >= 3; i -= 4) { s = (s >> 8) | (block[i] << 8); j = ftab[s] -1; ftab[s] = j; ptr[j] = i; s = (s >> 8) | (block[i-1] << 8); j = ftab[s] -1; ftab[s] = j; ptr[j] = i-1; s = (s >> 8) | (block[i-2] << 8); j = ftab[s] -1; ftab[s] = j; ptr[j] = i-2; s = (s >> 8) | (block[i-3] << 8); j = ftab[s] -1; ftab[s] = j; ptr[j] = i-3; } for (; i >= 0; i--) { s = (s >> 8) | (block[i] << 8); j = ftab[s] -1; ftab[s] = j; ptr[j] = i; } /*-- Now ftab contains the first loc of every small bucket. Calculate the running order, from smallest to largest big bucket. --*/ for (i = 0; i <= 255; i++) { bigDone [i] = False; runningOrder[i] = i; } { Int32 vv; Int32 h = 1; do h = 3 * h + 1; while (h <= 256); do { h = h / 3; for (i = h; i <= 255; i++) { vv = runningOrder[i]; j = i; while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { runningOrder[j] = runningOrder[j-h]; j = j - h; if (j <= (h - 1)) goto zero; } zero: runningOrder[j] = vv; } } while (h != 1); } /*-- The main sorting loop. --*/ numQSorted = 0; for (i = 0; i <= 255; i++) { /*-- Process big buckets, starting with the least full. Basically this is a 3-step process in which we call mainQSort3 to sort the small buckets [ss, j], but also make a big effort to avoid the calls if we can. --*/ ss = runningOrder[i]; /*-- Step 1: Complete the big bucket [ss] by quicksorting any unsorted small buckets [ss, j], for j != ss. Hopefully previous pointer-scanning phases have already completed many of the small buckets [ss, j], so we don't have to sort them at all. --*/ for (j = 0; j <= 255; j++) { if (j != ss) { sb = (ss << 8) + j; if ( ! (ftab[sb] & SETMASK) ) { Int32 lo = ftab[sb] & CLEARMASK; Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; if (hi > lo) { if (verb >= 4) VPrintf4 ( " qsort [0x%x, 0x%x] " "done %d this %d\n", ss, j, numQSorted, hi - lo + 1 ); mainQSort3 ( ptr, block, quadrant, nblock, lo, hi, BZ_N_RADIX, budget ); numQSorted += (hi - lo + 1); if (*budget < 0) return; } } ftab[sb] |= SETMASK; } } AssertH ( !bigDone[ss], 1006 ); /*-- Step 2: Now scan this big bucket [ss] so as to synthesise the sorted order for small buckets [t, ss] for all t, including, magically, the bucket [ss,ss] too. This will avoid doing Real Work in subsequent Step 1's. --*/ { for (j = 0; j <= 255; j++) { copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; } for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { k = ptr[j]-1; if (k < 0) k += nblock; c1 = block[k]; if (!bigDone[c1]) ptr[ copyStart[c1]++ ] = k; } for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { k = ptr[j]-1; if (k < 0) k += nblock; c1 = block[k]; if (!bigDone[c1]) ptr[ copyEnd[c1]-- ] = k; } } AssertH ( (copyStart[ss]-1 == copyEnd[ss]) || /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. Necessity for this case is demonstrated by compressing a sequence of approximately 48.5 million of character 251; 1.0.0/1.0.1 will then die here. */ (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), 1007 ) for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; /*-- Step 3: The [ss] big bucket is now done. Record this fact, and update the quadrant descriptors. Remember to update quadrants in the overshoot area too, if necessary. The "if (i < 255)" test merely skips this updating for the last bucket processed, since updating for the last bucket is pointless. The quadrant array provides a way to incrementally cache sort orderings, as they appear, so as to make subsequent comparisons in fullGtU() complete faster. For repetitive blocks this makes a big difference (but not big enough to be able to avoid the fallback sorting mechanism, exponential radix sort). The precise meaning is: at all times: for 0 <= i < nblock and 0 <= j <= nblock if block[i] != block[j], then the relative values of quadrant[i] and quadrant[j] are meaningless. else { if quadrant[i] < quadrant[j] then the string starting at i lexicographically precedes the string starting at j else if quadrant[i] > quadrant[j] then the string starting at j lexicographically precedes the string starting at i else the relative ordering of the strings starting at i and j has not yet been determined. } --*/ bigDone[ss] = True; if (i < 255) { Int32 bbStart = ftab[ss << 8] & CLEARMASK; Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; Int32 shifts = 0; while ((bbSize >> shifts) > 65534) shifts++; for (j = bbSize-1; j >= 0; j--) { Int32 a2update = ptr[bbStart + j]; UInt16 qVal = (UInt16)(j >> shifts); quadrant[a2update] = qVal; if (a2update < BZ_N_OVERSHOOT) quadrant[a2update + nblock] = qVal; } AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); } } if (verb >= 4) VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", nblock, numQSorted, nblock - numQSorted ); } #undef BIGFREQ #undef SETMASK #undef CLEARMASK /*---------------------------------------------*/ /* Pre: nblock > 0 arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] ((UChar*)arr2) [0 .. nblock-1] holds block arr1 exists for [0 .. nblock-1] Post: ((UChar*)arr2) [0 .. nblock-1] holds block All other areas of block destroyed ftab [ 0 .. 65536 ] destroyed arr1 [0 .. nblock-1] holds sorted order */ void BZ2_blockSort ( EState* s ) { UInt32* ptr = s->ptr; UChar* block = s->block; UInt32* ftab = s->ftab; Int32 nblock = s->nblock; Int32 verb = s->verbosity; Int32 wfact = s->workFactor; UInt16* quadrant; Int32 budget; Int32 budgetInit; Int32 i; if (nblock < 10000) { fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); } else { /* Calculate the location for quadrant, remembering to get the alignment right. Assumes that &(block[0]) is at least 2-byte aligned -- this should be ok since block is really the first section of arr2. */ i = nblock+BZ_N_OVERSHOOT; if (i & 1) i++; quadrant = (UInt16*)(&(block[i])); /* (wfact-1) / 3 puts the default-factor-30 transition point at very roughly the same place as with v0.1 and v0.9.0. Not that it particularly matters any more, since the resulting compressed stream is now the same regardless of whether or not we use the main sort or fallback sort. */ if (wfact < 1 ) wfact = 1; if (wfact > 100) wfact = 100; budgetInit = nblock * ((wfact-1) / 3); budget = budgetInit; mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); if (verb >= 3) VPrintf3 ( " %d work, %d block, ratio %5.2f\n", budgetInit - budget, nblock, (float)(budgetInit - budget) / (float)(nblock==0 ? 1 : nblock) ); if (budget < 0) { if (verb >= 2) VPrintf0 ( " too repetitive; using fallback" " sorting algorithm\n" ); fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); } } s->origPtr = -1; for (i = 0; i < s->nblock; i++) if (ptr[i] == 0) { s->origPtr = i; break; }; AssertH( s->origPtr != -1, 1003 ); } /*-------------------------------------------------------------*/ /*--- end blocksort.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/bzlib.c0000644000000000000000000013161007346545000013111 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Library top-level functions. ---*/ /*--- bzlib.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ /* CHANGES 0.9.0 -- original version. 0.9.0a/b -- no changes in this file. 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). fixed bzWrite/bzRead to ignore zero-length requests. fixed bzread to correctly handle read requests after EOF. wrong parameter order in call to bzDecompressInit in bzBuffToBuffDecompress. Fixed. */ #include "bzlib_private.h" /*---------------------------------------------------*/ /*--- Compression stuff ---*/ /*---------------------------------------------------*/ /*---------------------------------------------------*/ #ifndef BZ_NO_STDIO void BZ2_bz__AssertH__fail ( int errcode ) { fprintf(stderr, "\n\nbzip2/libbzip2: internal error number %d.\n" "This is a bug in bzip2/libbzip2, %s.\n" "Please report it to: bzip2-devel@sourceware.org. If this happened\n" "when you were using some program which uses libbzip2 as a\n" "component, you should also report this bug to the author(s)\n" "of that program. Please make an effort to report this bug;\n" "timely and accurate bug reports eventually lead to higher\n" "quality software. Thanks.\n\n", errcode, BZ2_bzlibVersion() ); if (errcode == 1007) { fprintf(stderr, "\n*** A special note about internal error number 1007 ***\n" "\n" "Experience suggests that a common cause of i.e. 1007\n" "is unreliable memory or other hardware. The 1007 assertion\n" "just happens to cross-check the results of huge numbers of\n" "memory reads/writes, and so acts (unintendedly) as a stress\n" "test of your memory system.\n" "\n" "I suggest the following: try compressing the file again,\n" "possibly monitoring progress in detail with the -vv flag.\n" "\n" "* If the error cannot be reproduced, and/or happens at different\n" " points in compression, you may have a flaky memory system.\n" " Try a memory-test program. I have used Memtest86\n" " (www.memtest86.com). At the time of writing it is free (GPLd).\n" " Memtest86 tests memory much more thorougly than your BIOSs\n" " power-on test, and may find failures that the BIOS doesn't.\n" "\n" "* If the error can be repeatably reproduced, this is a bug in\n" " bzip2, and I would very much like to hear about it. Please\n" " let me know, and, ideally, save a copy of the file causing the\n" " problem -- without which I will be unable to investigate it.\n" "\n" ); } exit(3); } #endif /*---------------------------------------------------*/ static int bz_config_ok ( void ) { if (sizeof(int) != 4) return 0; if (sizeof(short) != 2) return 0; if (sizeof(char) != 1) return 0; return 1; } /*---------------------------------------------------*/ static void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) { void* v = malloc ( items * size ); return v; } static void default_bzfree ( void* opaque, void* addr ) { if (addr != NULL) free ( addr ); } /*---------------------------------------------------*/ static void prepare_new_block ( EState* s ) { Int32 i; s->nblock = 0; s->numZ = 0; s->state_out_pos = 0; BZ_INITIALISE_CRC ( s->blockCRC ); for (i = 0; i < 256; i++) s->inUse[i] = False; s->blockNo++; } /*---------------------------------------------------*/ static void init_RL ( EState* s ) { s->state_in_ch = 256; s->state_in_len = 0; } static Bool isempty_RL ( EState* s ) { if (s->state_in_ch < 256 && s->state_in_len > 0) return False; else return True; } /*---------------------------------------------------*/ int BZ_API(BZ2_bzCompressInit) ( bz_stream* strm, int blockSize100k, int verbosity, int workFactor ) { Int32 n; EState* s; if (!bz_config_ok()) return BZ_CONFIG_ERROR; if (strm == NULL || blockSize100k < 1 || blockSize100k > 9 || workFactor < 0 || workFactor > 250) return BZ_PARAM_ERROR; if (workFactor == 0) workFactor = 30; if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; if (strm->bzfree == NULL) strm->bzfree = default_bzfree; s = BZALLOC( sizeof(EState) ); if (s == NULL) return BZ_MEM_ERROR; s->strm = strm; s->arr1 = NULL; s->arr2 = NULL; s->ftab = NULL; n = 100000 * blockSize100k; s->arr1 = BZALLOC( n * sizeof(UInt32) ); s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { if (s->arr1 != NULL) BZFREE(s->arr1); if (s->arr2 != NULL) BZFREE(s->arr2); if (s->ftab != NULL) BZFREE(s->ftab); if (s != NULL) BZFREE(s); return BZ_MEM_ERROR; } s->blockNo = 0; s->state = BZ_S_INPUT; s->mode = BZ_M_RUNNING; s->combinedCRC = 0; s->blockSize100k = blockSize100k; s->nblockMAX = 100000 * blockSize100k - 19; s->verbosity = verbosity; s->workFactor = workFactor; s->block = (UChar*)s->arr2; s->mtfv = (UInt16*)s->arr1; s->zbits = NULL; s->ptr = (UInt32*)s->arr1; strm->state = s; strm->total_in_lo32 = 0; strm->total_in_hi32 = 0; strm->total_out_lo32 = 0; strm->total_out_hi32 = 0; init_RL ( s ); prepare_new_block ( s ); return BZ_OK; } /*---------------------------------------------------*/ static void add_pair_to_block ( EState* s ) { Int32 i; UChar ch = (UChar)(s->state_in_ch); for (i = 0; i < s->state_in_len; i++) { BZ_UPDATE_CRC( s->blockCRC, ch ); } s->inUse[s->state_in_ch] = True; switch (s->state_in_len) { case 1: s->block[s->nblock] = (UChar)ch; s->nblock++; break; case 2: s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = (UChar)ch; s->nblock++; break; case 3: s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = (UChar)ch; s->nblock++; break; default: s->inUse[s->state_in_len-4] = True; s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = (UChar)ch; s->nblock++; s->block[s->nblock] = ((UChar)(s->state_in_len-4)); s->nblock++; break; } } /*---------------------------------------------------*/ static void flush_RL ( EState* s ) { if (s->state_in_ch < 256) add_pair_to_block ( s ); init_RL ( s ); } /*---------------------------------------------------*/ #define ADD_CHAR_TO_BLOCK(zs,zchh0) \ { \ UInt32 zchh = (UInt32)(zchh0); \ /*-- fast track the common case --*/ \ if (zchh != zs->state_in_ch && \ zs->state_in_len == 1) { \ UChar ch = (UChar)(zs->state_in_ch); \ BZ_UPDATE_CRC( zs->blockCRC, ch ); \ zs->inUse[zs->state_in_ch] = True; \ zs->block[zs->nblock] = (UChar)ch; \ zs->nblock++; \ zs->state_in_ch = zchh; \ } \ else \ /*-- general, uncommon cases --*/ \ if (zchh != zs->state_in_ch || \ zs->state_in_len == 255) { \ if (zs->state_in_ch < 256) \ add_pair_to_block ( zs ); \ zs->state_in_ch = zchh; \ zs->state_in_len = 1; \ } else { \ zs->state_in_len++; \ } \ } /*---------------------------------------------------*/ static Bool copy_input_until_stop ( EState* s ) { Bool progress_in = False; if (s->mode == BZ_M_RUNNING) { /*-- fast track the common case --*/ while (True) { /*-- block full? --*/ if (s->nblock >= s->nblockMAX) break; /*-- no input? --*/ if (s->strm->avail_in == 0) break; progress_in = True; ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; } } else { /*-- general, uncommon case --*/ while (True) { /*-- block full? --*/ if (s->nblock >= s->nblockMAX) break; /*-- no input? --*/ if (s->strm->avail_in == 0) break; /*-- flush/finish end? --*/ if (s->avail_in_expect == 0) break; progress_in = True; ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); s->strm->next_in++; s->strm->avail_in--; s->strm->total_in_lo32++; if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; s->avail_in_expect--; } } return progress_in; } /*---------------------------------------------------*/ static Bool copy_output_until_stop ( EState* s ) { Bool progress_out = False; while (True) { /*-- no output space? --*/ if (s->strm->avail_out == 0) break; /*-- block done? --*/ if (s->state_out_pos >= s->numZ) break; progress_out = True; *(s->strm->next_out) = s->zbits[s->state_out_pos]; s->state_out_pos++; s->strm->avail_out--; s->strm->next_out++; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } return progress_out; } /*---------------------------------------------------*/ static Bool handle_compress ( bz_stream* strm ) { Bool progress_in = False; Bool progress_out = False; EState* s = strm->state; while (True) { if (s->state == BZ_S_OUTPUT) { progress_out |= copy_output_until_stop ( s ); if (s->state_out_pos < s->numZ) break; if (s->mode == BZ_M_FINISHING && s->avail_in_expect == 0 && isempty_RL(s)) break; prepare_new_block ( s ); s->state = BZ_S_INPUT; if (s->mode == BZ_M_FLUSHING && s->avail_in_expect == 0 && isempty_RL(s)) break; } if (s->state == BZ_S_INPUT) { progress_in |= copy_input_until_stop ( s ); if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { flush_RL ( s ); BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); s->state = BZ_S_OUTPUT; } else if (s->nblock >= s->nblockMAX) { BZ2_compressBlock ( s, False ); s->state = BZ_S_OUTPUT; } else if (s->strm->avail_in == 0) { break; } } } return progress_in || progress_out; } /*---------------------------------------------------*/ int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) { Bool progress; EState* s; if (strm == NULL) return BZ_PARAM_ERROR; s = strm->state; if (s == NULL) return BZ_PARAM_ERROR; if (s->strm != strm) return BZ_PARAM_ERROR; preswitch: switch (s->mode) { case BZ_M_IDLE: return BZ_SEQUENCE_ERROR; case BZ_M_RUNNING: if (action == BZ_RUN) { progress = handle_compress ( strm ); return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; } else if (action == BZ_FLUSH) { s->avail_in_expect = strm->avail_in; s->mode = BZ_M_FLUSHING; goto preswitch; } else if (action == BZ_FINISH) { s->avail_in_expect = strm->avail_in; s->mode = BZ_M_FINISHING; goto preswitch; } else return BZ_PARAM_ERROR; case BZ_M_FLUSHING: if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; if (s->avail_in_expect != s->strm->avail_in) return BZ_SEQUENCE_ERROR; progress = handle_compress ( strm ); if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) return BZ_FLUSH_OK; s->mode = BZ_M_RUNNING; return BZ_RUN_OK; case BZ_M_FINISHING: if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; if (s->avail_in_expect != s->strm->avail_in) return BZ_SEQUENCE_ERROR; progress = handle_compress ( strm ); if (!progress) return BZ_SEQUENCE_ERROR; if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) return BZ_FINISH_OK; s->mode = BZ_M_IDLE; return BZ_STREAM_END; } return BZ_OK; /*--not reached--*/ } /*---------------------------------------------------*/ int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) { EState* s; if (strm == NULL) return BZ_PARAM_ERROR; s = strm->state; if (s == NULL) return BZ_PARAM_ERROR; if (s->strm != strm) return BZ_PARAM_ERROR; if (s->arr1 != NULL) BZFREE(s->arr1); if (s->arr2 != NULL) BZFREE(s->arr2); if (s->ftab != NULL) BZFREE(s->ftab); BZFREE(strm->state); strm->state = NULL; return BZ_OK; } /*---------------------------------------------------*/ /*--- Decompression stuff ---*/ /*---------------------------------------------------*/ /*---------------------------------------------------*/ int BZ_API(BZ2_bzDecompressInit) ( bz_stream* strm, int verbosity, int small ) { DState* s; if (!bz_config_ok()) return BZ_CONFIG_ERROR; if (strm == NULL) return BZ_PARAM_ERROR; if (small != 0 && small != 1) return BZ_PARAM_ERROR; if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; if (strm->bzfree == NULL) strm->bzfree = default_bzfree; s = BZALLOC( sizeof(DState) ); if (s == NULL) return BZ_MEM_ERROR; s->strm = strm; strm->state = s; s->state = BZ_X_MAGIC_1; s->bsLive = 0; s->bsBuff = 0; s->calculatedCombinedCRC = 0; strm->total_in_lo32 = 0; strm->total_in_hi32 = 0; strm->total_out_lo32 = 0; strm->total_out_hi32 = 0; s->smallDecompress = (Bool)small; s->ll4 = NULL; s->ll16 = NULL; s->tt = NULL; s->currBlockNo = 0; s->verbosity = verbosity; return BZ_OK; } /*---------------------------------------------------*/ /* Return True iff data corruption is discovered. Returns False if there is no problem. */ static Bool unRLE_obuf_to_output_FAST ( DState* s ) { UChar k1; if (s->blockRandomised) { while (True) { /* try to finish existing run */ while (True) { if (s->strm->avail_out == 0) return False; if (s->state_out_len == 0) break; *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); s->state_out_len--; s->strm->next_out++; s->strm->avail_out--; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } /* can a new run be started? */ if (s->nblock_used == s->save_nblock+1) return False; /* Only caused by corrupt data stream? */ if (s->nblock_used > s->save_nblock+1) return True; s->state_out_len = 1; s->state_out_ch = s->k0; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 2; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 3; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; s->state_out_len = ((Int32)k1) + 4; BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; s->nblock_used++; } } else { /* restore */ UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; UChar c_state_out_ch = s->state_out_ch; Int32 c_state_out_len = s->state_out_len; Int32 c_nblock_used = s->nblock_used; Int32 c_k0 = s->k0; UInt32* c_tt = s->tt; UInt32 c_tPos = s->tPos; char* cs_next_out = s->strm->next_out; unsigned int cs_avail_out = s->strm->avail_out; Int32 ro_blockSize100k = s->blockSize100k; /* end restore */ UInt32 avail_out_INIT = cs_avail_out; Int32 s_save_nblockPP = s->save_nblock+1; unsigned int total_out_lo32_old; while (True) { /* try to finish existing run */ if (c_state_out_len > 0) { while (True) { if (cs_avail_out == 0) goto return_notr; if (c_state_out_len == 1) break; *( (UChar*)(cs_next_out) ) = c_state_out_ch; BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); c_state_out_len--; cs_next_out++; cs_avail_out--; } s_state_out_len_eq_one: { if (cs_avail_out == 0) { c_state_out_len = 1; goto return_notr; }; *( (UChar*)(cs_next_out) ) = c_state_out_ch; BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); cs_next_out++; cs_avail_out--; } } /* Only caused by corrupt data stream? */ if (c_nblock_used > s_save_nblockPP) return True; /* can a new run be started? */ if (c_nblock_used == s_save_nblockPP) { c_state_out_len = 0; goto return_notr; }; c_state_out_ch = c_k0; BZ_GET_FAST_C(k1); c_nblock_used++; if (k1 != c_k0) { c_k0 = k1; goto s_state_out_len_eq_one; }; if (c_nblock_used == s_save_nblockPP) goto s_state_out_len_eq_one; c_state_out_len = 2; BZ_GET_FAST_C(k1); c_nblock_used++; if (c_nblock_used == s_save_nblockPP) continue; if (k1 != c_k0) { c_k0 = k1; continue; }; c_state_out_len = 3; BZ_GET_FAST_C(k1); c_nblock_used++; if (c_nblock_used == s_save_nblockPP) continue; if (k1 != c_k0) { c_k0 = k1; continue; }; BZ_GET_FAST_C(k1); c_nblock_used++; c_state_out_len = ((Int32)k1) + 4; BZ_GET_FAST_C(c_k0); c_nblock_used++; } return_notr: total_out_lo32_old = s->strm->total_out_lo32; s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); if (s->strm->total_out_lo32 < total_out_lo32_old) s->strm->total_out_hi32++; /* save */ s->calculatedBlockCRC = c_calculatedBlockCRC; s->state_out_ch = c_state_out_ch; s->state_out_len = c_state_out_len; s->nblock_used = c_nblock_used; s->k0 = c_k0; s->tt = c_tt; s->tPos = c_tPos; s->strm->next_out = cs_next_out; s->strm->avail_out = cs_avail_out; /* end save */ } return False; } /*---------------------------------------------------*/ __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) { Int32 nb, na, mid; nb = 0; na = 256; do { mid = (nb + na) >> 1; if (indx >= cftab[mid]) nb = mid; else na = mid; } while (na - nb != 1); return nb; } /*---------------------------------------------------*/ /* Return True iff data corruption is discovered. Returns False if there is no problem. */ static Bool unRLE_obuf_to_output_SMALL ( DState* s ) { UChar k1; if (s->blockRandomised) { while (True) { /* try to finish existing run */ while (True) { if (s->strm->avail_out == 0) return False; if (s->state_out_len == 0) break; *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); s->state_out_len--; s->strm->next_out++; s->strm->avail_out--; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } /* can a new run be started? */ if (s->nblock_used == s->save_nblock+1) return False; /* Only caused by corrupt data stream? */ if (s->nblock_used > s->save_nblock+1) return True; s->state_out_len = 1; s->state_out_ch = s->k0; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 2; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 3; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; s->state_out_len = ((Int32)k1) + 4; BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; s->nblock_used++; } } else { while (True) { /* try to finish existing run */ while (True) { if (s->strm->avail_out == 0) return False; if (s->state_out_len == 0) break; *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); s->state_out_len--; s->strm->next_out++; s->strm->avail_out--; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } /* can a new run be started? */ if (s->nblock_used == s->save_nblock+1) return False; /* Only caused by corrupt data stream? */ if (s->nblock_used > s->save_nblock+1) return True; s->state_out_len = 1; s->state_out_ch = s->k0; BZ_GET_SMALL(k1); s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 2; BZ_GET_SMALL(k1); s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 3; BZ_GET_SMALL(k1); s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; BZ_GET_SMALL(k1); s->nblock_used++; s->state_out_len = ((Int32)k1) + 4; BZ_GET_SMALL(s->k0); s->nblock_used++; } } } /*---------------------------------------------------*/ int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) { Bool corrupt; DState* s; if (strm == NULL) return BZ_PARAM_ERROR; s = strm->state; if (s == NULL) return BZ_PARAM_ERROR; if (s->strm != strm) return BZ_PARAM_ERROR; while (True) { if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; if (s->state == BZ_X_OUTPUT) { if (s->smallDecompress) corrupt = unRLE_obuf_to_output_SMALL ( s ); else corrupt = unRLE_obuf_to_output_FAST ( s ); if (corrupt) return BZ_DATA_ERROR; if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { BZ_FINALISE_CRC ( s->calculatedBlockCRC ); if (s->verbosity >= 3) VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, s->calculatedBlockCRC ); if (s->verbosity >= 2) VPrintf0 ( "]" ); if (s->calculatedBlockCRC != s->storedBlockCRC) return BZ_DATA_ERROR; s->calculatedCombinedCRC = (s->calculatedCombinedCRC << 1) | (s->calculatedCombinedCRC >> 31); s->calculatedCombinedCRC ^= s->calculatedBlockCRC; s->state = BZ_X_BLKHDR_1; } else { return BZ_OK; } } if (s->state >= BZ_X_MAGIC_1) { Int32 r = BZ2_decompress ( s ); if (r == BZ_STREAM_END) { if (s->verbosity >= 3) VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", s->storedCombinedCRC, s->calculatedCombinedCRC ); if (s->calculatedCombinedCRC != s->storedCombinedCRC) return BZ_DATA_ERROR; return r; } if (s->state != BZ_X_OUTPUT) return r; } } AssertH ( 0, 6001 ); return 0; /*NOTREACHED*/ } /*---------------------------------------------------*/ int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) { DState* s; if (strm == NULL) return BZ_PARAM_ERROR; s = strm->state; if (s == NULL) return BZ_PARAM_ERROR; if (s->strm != strm) return BZ_PARAM_ERROR; if (s->tt != NULL) BZFREE(s->tt); if (s->ll16 != NULL) BZFREE(s->ll16); if (s->ll4 != NULL) BZFREE(s->ll4); BZFREE(strm->state); strm->state = NULL; return BZ_OK; } #ifndef BZ_NO_STDIO /*---------------------------------------------------*/ /*--- File I/O stuff ---*/ /*---------------------------------------------------*/ #define BZ_SETERR(eee) \ { \ if (bzerror != NULL) *bzerror = eee; \ if (bzf != NULL) bzf->lastErr = eee; \ } typedef struct { FILE* handle; Char buf[BZ_MAX_UNUSED]; Int32 bufN; Bool writing; bz_stream strm; Int32 lastErr; Bool initialisedOk; } bzFile; /*---------------------------------------------*/ static Bool myfeof ( FILE* f ) { Int32 c = fgetc ( f ); if (c == EOF) return True; ungetc ( c, f ); return False; } /*---------------------------------------------------*/ BZFILE* BZ_API(BZ2_bzWriteOpen) ( int* bzerror, FILE* f, int blockSize100k, int verbosity, int workFactor ) { Int32 ret; bzFile* bzf = NULL; BZ_SETERR(BZ_OK); if (f == NULL || (blockSize100k < 1 || blockSize100k > 9) || (workFactor < 0 || workFactor > 250) || (verbosity < 0 || verbosity > 4)) { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; if (ferror(f)) { BZ_SETERR(BZ_IO_ERROR); return NULL; }; bzf = malloc ( sizeof(bzFile) ); if (bzf == NULL) { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; BZ_SETERR(BZ_OK); bzf->initialisedOk = False; bzf->bufN = 0; bzf->handle = f; bzf->writing = True; bzf->strm.bzalloc = NULL; bzf->strm.bzfree = NULL; bzf->strm.opaque = NULL; if (workFactor == 0) workFactor = 30; ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, verbosity, workFactor ); if (ret != BZ_OK) { BZ_SETERR(ret); free(bzf); return NULL; }; bzf->strm.avail_in = 0; bzf->initialisedOk = True; return bzf; } /*---------------------------------------------------*/ void BZ_API(BZ2_bzWrite) ( int* bzerror, BZFILE* b, void* buf, int len ) { Int32 n, n2, ret; bzFile* bzf = (bzFile*)b; BZ_SETERR(BZ_OK); if (bzf == NULL || buf == NULL || len < 0) { BZ_SETERR(BZ_PARAM_ERROR); return; }; if (!(bzf->writing)) { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return; }; if (len == 0) { BZ_SETERR(BZ_OK); return; }; bzf->strm.avail_in = len; bzf->strm.next_in = buf; while (True) { bzf->strm.avail_out = BZ_MAX_UNUSED; bzf->strm.next_out = bzf->buf; ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); if (ret != BZ_RUN_OK) { BZ_SETERR(ret); return; }; if (bzf->strm.avail_out < BZ_MAX_UNUSED) { n = BZ_MAX_UNUSED - bzf->strm.avail_out; n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), n, bzf->handle ); if (n != n2 || ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return; }; } if (bzf->strm.avail_in == 0) { BZ_SETERR(BZ_OK); return; }; } } /*---------------------------------------------------*/ void BZ_API(BZ2_bzWriteClose) ( int* bzerror, BZFILE* b, int abandon, unsigned int* nbytes_in, unsigned int* nbytes_out ) { BZ2_bzWriteClose64 ( bzerror, b, abandon, nbytes_in, NULL, nbytes_out, NULL ); } void BZ_API(BZ2_bzWriteClose64) ( int* bzerror, BZFILE* b, int abandon, unsigned int* nbytes_in_lo32, unsigned int* nbytes_in_hi32, unsigned int* nbytes_out_lo32, unsigned int* nbytes_out_hi32 ) { Int32 n, n2, ret; bzFile* bzf = (bzFile*)b; if (bzf == NULL) { BZ_SETERR(BZ_OK); return; }; if (!(bzf->writing)) { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return; }; if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; if ((!abandon) && bzf->lastErr == BZ_OK) { while (True) { bzf->strm.avail_out = BZ_MAX_UNUSED; bzf->strm.next_out = bzf->buf; ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) { BZ_SETERR(ret); return; }; if (bzf->strm.avail_out < BZ_MAX_UNUSED) { n = BZ_MAX_UNUSED - bzf->strm.avail_out; n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), n, bzf->handle ); if (n != n2 || ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return; }; } if (ret == BZ_STREAM_END) break; } } if ( !abandon && !ferror ( bzf->handle ) ) { fflush ( bzf->handle ); if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return; }; } if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = bzf->strm.total_in_lo32; if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = bzf->strm.total_in_hi32; if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = bzf->strm.total_out_lo32; if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = bzf->strm.total_out_hi32; BZ_SETERR(BZ_OK); BZ2_bzCompressEnd ( &(bzf->strm) ); free ( bzf ); } /*---------------------------------------------------*/ BZFILE* BZ_API(BZ2_bzReadOpen) ( int* bzerror, FILE* f, int verbosity, int small, void* unused, int nUnused ) { bzFile* bzf = NULL; int ret; BZ_SETERR(BZ_OK); if (f == NULL || (small != 0 && small != 1) || (verbosity < 0 || verbosity > 4) || (unused == NULL && nUnused != 0) || (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; if (ferror(f)) { BZ_SETERR(BZ_IO_ERROR); return NULL; }; bzf = malloc ( sizeof(bzFile) ); if (bzf == NULL) { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; BZ_SETERR(BZ_OK); bzf->initialisedOk = False; bzf->handle = f; bzf->bufN = 0; bzf->writing = False; bzf->strm.bzalloc = NULL; bzf->strm.bzfree = NULL; bzf->strm.opaque = NULL; while (nUnused > 0) { bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; unused = ((void*)( 1 + ((UChar*)(unused)) )); nUnused--; } ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); if (ret != BZ_OK) { BZ_SETERR(ret); free(bzf); return NULL; }; bzf->strm.avail_in = bzf->bufN; bzf->strm.next_in = bzf->buf; bzf->initialisedOk = True; return bzf; } /*---------------------------------------------------*/ void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) { bzFile* bzf = (bzFile*)b; BZ_SETERR(BZ_OK); if (bzf == NULL) { BZ_SETERR(BZ_OK); return; }; if (bzf->writing) { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; if (bzf->initialisedOk) (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); free ( bzf ); } /*---------------------------------------------------*/ int BZ_API(BZ2_bzRead) ( int* bzerror, BZFILE* b, void* buf, int len ) { Int32 n, ret; bzFile* bzf = (bzFile*)b; BZ_SETERR(BZ_OK); if (bzf == NULL || buf == NULL || len < 0) { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; if (bzf->writing) { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; if (len == 0) { BZ_SETERR(BZ_OK); return 0; }; bzf->strm.avail_out = len; bzf->strm.next_out = buf; while (True) { if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return 0; }; if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { n = fread ( bzf->buf, sizeof(UChar), BZ_MAX_UNUSED, bzf->handle ); if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return 0; }; bzf->bufN = n; bzf->strm.avail_in = bzf->bufN; bzf->strm.next_in = bzf->buf; } ret = BZ2_bzDecompress ( &(bzf->strm) ); if (ret != BZ_OK && ret != BZ_STREAM_END) { BZ_SETERR(ret); return 0; }; if (ret == BZ_OK && myfeof(bzf->handle) && bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; if (ret == BZ_STREAM_END) { BZ_SETERR(BZ_STREAM_END); return len - bzf->strm.avail_out; }; if (bzf->strm.avail_out == 0) { BZ_SETERR(BZ_OK); return len; }; } return 0; /*not reached*/ } /*---------------------------------------------------*/ void BZ_API(BZ2_bzReadGetUnused) ( int* bzerror, BZFILE* b, void** unused, int* nUnused ) { bzFile* bzf = (bzFile*)b; if (bzf == NULL) { BZ_SETERR(BZ_PARAM_ERROR); return; }; if (bzf->lastErr != BZ_STREAM_END) { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; if (unused == NULL || nUnused == NULL) { BZ_SETERR(BZ_PARAM_ERROR); return; }; BZ_SETERR(BZ_OK); *nUnused = bzf->strm.avail_in; *unused = bzf->strm.next_in; } #endif /*---------------------------------------------------*/ /*--- Misc convenience stuff ---*/ /*---------------------------------------------------*/ /*---------------------------------------------------*/ int BZ_API(BZ2_bzBuffToBuffCompress) ( char* dest, unsigned int* destLen, char* source, unsigned int sourceLen, int blockSize100k, int verbosity, int workFactor ) { bz_stream strm; int ret; if (dest == NULL || destLen == NULL || source == NULL || blockSize100k < 1 || blockSize100k > 9 || verbosity < 0 || verbosity > 4 || workFactor < 0 || workFactor > 250) return BZ_PARAM_ERROR; if (workFactor == 0) workFactor = 30; strm.bzalloc = NULL; strm.bzfree = NULL; strm.opaque = NULL; ret = BZ2_bzCompressInit ( &strm, blockSize100k, verbosity, workFactor ); if (ret != BZ_OK) return ret; strm.next_in = source; strm.next_out = dest; strm.avail_in = sourceLen; strm.avail_out = *destLen; ret = BZ2_bzCompress ( &strm, BZ_FINISH ); if (ret == BZ_FINISH_OK) goto output_overflow; if (ret != BZ_STREAM_END) goto errhandler; /* normal termination */ *destLen -= strm.avail_out; BZ2_bzCompressEnd ( &strm ); return BZ_OK; output_overflow: BZ2_bzCompressEnd ( &strm ); return BZ_OUTBUFF_FULL; errhandler: BZ2_bzCompressEnd ( &strm ); return ret; } /*---------------------------------------------------*/ int BZ_API(BZ2_bzBuffToBuffDecompress) ( char* dest, unsigned int* destLen, char* source, unsigned int sourceLen, int small, int verbosity ) { bz_stream strm; int ret; if (dest == NULL || destLen == NULL || source == NULL || (small != 0 && small != 1) || verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; strm.bzalloc = NULL; strm.bzfree = NULL; strm.opaque = NULL; ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); if (ret != BZ_OK) return ret; strm.next_in = source; strm.next_out = dest; strm.avail_in = sourceLen; strm.avail_out = *destLen; ret = BZ2_bzDecompress ( &strm ); if (ret == BZ_OK) goto output_overflow_or_eof; if (ret != BZ_STREAM_END) goto errhandler; /* normal termination */ *destLen -= strm.avail_out; BZ2_bzDecompressEnd ( &strm ); return BZ_OK; output_overflow_or_eof: if (strm.avail_out > 0) { BZ2_bzDecompressEnd ( &strm ); return BZ_UNEXPECTED_EOF; } else { BZ2_bzDecompressEnd ( &strm ); return BZ_OUTBUFF_FULL; }; errhandler: BZ2_bzDecompressEnd ( &strm ); return ret; } /*---------------------------------------------------*/ /*-- Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) to support better zlib compatibility. This code is not _officially_ part of libbzip2 (yet); I haven't tested it, documented it, or considered the threading-safeness of it. If this code breaks, please contact both Yoshioka and me. --*/ /*---------------------------------------------------*/ /*---------------------------------------------------*/ /*-- return version like "0.9.5d, 4-Sept-1999". --*/ const char * BZ_API(BZ2_bzlibVersion)(void) { return BZ_VERSION; } #ifndef BZ_NO_STDIO /*---------------------------------------------------*/ #if defined(_WIN32) || defined(OS2) || defined(MSDOS) # include # include # define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) #else # define SET_BINARY_MODE(file) #endif static BZFILE * bzopen_or_bzdopen ( const char *path, /* no use when bzdopen */ int fd, /* no use when bzdopen */ const char *mode, int open_mode) /* bzopen: 0, bzdopen:1 */ { int bzerr; char unused[BZ_MAX_UNUSED]; int blockSize100k = 9; int writing = 0; char mode2[10] = ""; FILE *fp = NULL; BZFILE *bzfp = NULL; int verbosity = 0; int workFactor = 30; int smallMode = 0; int nUnused = 0; if (mode == NULL) return NULL; while (*mode) { switch (*mode) { case 'r': writing = 0; break; case 'w': writing = 1; break; case 's': smallMode = 1; break; default: if (isdigit((int)(*mode))) { blockSize100k = *mode-BZ_HDR_0; } } mode++; } strcat(mode2, writing ? "w" : "r" ); strcat(mode2,"b"); /* binary mode */ if (open_mode==0) { if (path==NULL || strcmp(path,"")==0) { fp = (writing ? stdout : stdin); SET_BINARY_MODE(fp); } else { fp = fopen(path,mode2); } } else { #ifdef BZ_STRICT_ANSI fp = NULL; #else fp = fdopen(fd,mode2); #endif } if (fp == NULL) return NULL; if (writing) { /* Guard against total chaos and anarchy -- JRS */ if (blockSize100k < 1) blockSize100k = 1; if (blockSize100k > 9) blockSize100k = 9; bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, verbosity,workFactor); } else { bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, unused,nUnused); } if (bzfp == NULL) { if (fp != stdin && fp != stdout) fclose(fp); return NULL; } return bzfp; } /*---------------------------------------------------*/ /*-- open file for read or write. ex) bzopen("file","w9") case path="" or NULL => use stdin or stdout. --*/ BZFILE * BZ_API(BZ2_bzopen) ( const char *path, const char *mode ) { return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); } /*---------------------------------------------------*/ BZFILE * BZ_API(BZ2_bzdopen) ( int fd, const char *mode ) { return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); } /*---------------------------------------------------*/ int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) { int bzerr, nread; if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; nread = BZ2_bzRead(&bzerr,b,buf,len); if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { return nread; } else { return -1; } } /*---------------------------------------------------*/ int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) { int bzerr; BZ2_bzWrite(&bzerr,b,buf,len); if(bzerr == BZ_OK){ return len; }else{ return -1; } } /*---------------------------------------------------*/ int BZ_API(BZ2_bzflush) (BZFILE *b) { /* do nothing now... */ return 0; } /*---------------------------------------------------*/ void BZ_API(BZ2_bzclose) (BZFILE* b) { int bzerr; FILE *fp; if (b==NULL) {return;} fp = ((bzFile *)b)->handle; if(((bzFile*)b)->writing){ BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); if(bzerr != BZ_OK){ BZ2_bzWriteClose(NULL,b,1,NULL,NULL); } }else{ BZ2_bzReadClose(&bzerr,b); } if(fp!=stdin && fp!=stdout){ fclose(fp); } } /*---------------------------------------------------*/ /*-- return last error code --*/ static const char *bzerrorstrings[] = { "OK" ,"SEQUENCE_ERROR" ,"PARAM_ERROR" ,"MEM_ERROR" ,"DATA_ERROR" ,"DATA_ERROR_MAGIC" ,"IO_ERROR" ,"UNEXPECTED_EOF" ,"OUTBUFF_FULL" ,"CONFIG_ERROR" ,"???" /* for future */ ,"???" /* for future */ ,"???" /* for future */ ,"???" /* for future */ ,"???" /* for future */ ,"???" /* for future */ }; const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) { int err = ((bzFile *)b)->lastErr; if(err>0) err = 0; *errnum = err; return bzerrorstrings[err*-1]; } #endif /*-------------------------------------------------------------*/ /*--- end bzlib.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/bzlib.h0000644000000000000000000001414007346545000013114 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Public header file for the library. ---*/ /*--- bzlib.h ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #ifndef _BZLIB_H #define _BZLIB_H #ifdef __cplusplus extern "C" { #endif #define BZ_RUN 0 #define BZ_FLUSH 1 #define BZ_FINISH 2 #define BZ_OK 0 #define BZ_RUN_OK 1 #define BZ_FLUSH_OK 2 #define BZ_FINISH_OK 3 #define BZ_STREAM_END 4 #define BZ_SEQUENCE_ERROR (-1) #define BZ_PARAM_ERROR (-2) #define BZ_MEM_ERROR (-3) #define BZ_DATA_ERROR (-4) #define BZ_DATA_ERROR_MAGIC (-5) #define BZ_IO_ERROR (-6) #define BZ_UNEXPECTED_EOF (-7) #define BZ_OUTBUFF_FULL (-8) #define BZ_CONFIG_ERROR (-9) typedef struct { char *next_in; unsigned int avail_in; unsigned int total_in_lo32; unsigned int total_in_hi32; char *next_out; unsigned int avail_out; unsigned int total_out_lo32; unsigned int total_out_hi32; void *state; void *(*bzalloc)(void *,int,int); void (*bzfree)(void *,void *); void *opaque; } bz_stream; #ifndef BZ_IMPORT #define BZ_EXPORT #endif #ifndef BZ_NO_STDIO /* Need a definitition for FILE */ #include #endif #ifdef _WIN32 # include # ifdef small /* windows.h define small to char */ # undef small # endif # ifdef BZ_EXPORT # define BZ_API(func) WINAPI func # define BZ_EXTERN extern # else /* import windows dll dynamically */ # define BZ_API(func) (WINAPI * func) # define BZ_EXTERN # endif #else # define BZ_API(func) func # define BZ_EXTERN extern #endif /*-- Core (low-level) library functions --*/ BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( bz_stream* strm, int blockSize100k, int verbosity, int workFactor ); BZ_EXTERN int BZ_API(BZ2_bzCompress) ( bz_stream* strm, int action ); BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( bz_stream* strm ); BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( bz_stream *strm, int verbosity, int small ); BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( bz_stream* strm ); BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ); /*-- High(er) level library functions --*/ #ifndef BZ_NO_STDIO #define BZ_MAX_UNUSED 5000 typedef void BZFILE; BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( int* bzerror, FILE* f, int verbosity, int small, void* unused, int nUnused ); BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( int* bzerror, BZFILE* b ); BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( int* bzerror, BZFILE* b, void** unused, int* nUnused ); BZ_EXTERN int BZ_API(BZ2_bzRead) ( int* bzerror, BZFILE* b, void* buf, int len ); BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( int* bzerror, FILE* f, int blockSize100k, int verbosity, int workFactor ); BZ_EXTERN void BZ_API(BZ2_bzWrite) ( int* bzerror, BZFILE* b, void* buf, int len ); BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( int* bzerror, BZFILE* b, int abandon, unsigned int* nbytes_in, unsigned int* nbytes_out ); BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( int* bzerror, BZFILE* b, int abandon, unsigned int* nbytes_in_lo32, unsigned int* nbytes_in_hi32, unsigned int* nbytes_out_lo32, unsigned int* nbytes_out_hi32 ); #endif /*-- Utility functions --*/ BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( char* dest, unsigned int* destLen, char* source, unsigned int sourceLen, int blockSize100k, int verbosity, int workFactor ); BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( char* dest, unsigned int* destLen, char* source, unsigned int sourceLen, int small, int verbosity ); /*-- Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) to support better zlib compatibility. This code is not _officially_ part of libbzip2 (yet); I haven't tested it, documented it, or considered the threading-safeness of it. If this code breaks, please contact both Yoshioka and me. --*/ BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( void ); #ifndef BZ_NO_STDIO BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( const char *path, const char *mode ); BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( int fd, const char *mode ); BZ_EXTERN int BZ_API(BZ2_bzread) ( BZFILE* b, void* buf, int len ); BZ_EXTERN int BZ_API(BZ2_bzwrite) ( BZFILE* b, void* buf, int len ); BZ_EXTERN int BZ_API(BZ2_bzflush) ( BZFILE* b ); BZ_EXTERN void BZ_API(BZ2_bzclose) ( BZFILE* b ); BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( BZFILE *b, int *errnum ); #endif #ifdef __cplusplus } #endif #endif /*-------------------------------------------------------------*/ /*--- end bzlib.h ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/bzlib_private.h0000755000000000000000000003166707346545000014666 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Private header file for the library. ---*/ /*--- bzlib_private.h ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #ifndef _BZLIB_PRIVATE_H #define _BZLIB_PRIVATE_H #include #ifndef BZ_NO_STDIO #include #include #include #endif #include "bzlib.h" /*-- General stuff. --*/ #define BZ_VERSION "1.0.8, 13-Jul-2019" typedef char Char; typedef unsigned char Bool; typedef unsigned char UChar; typedef int Int32; typedef unsigned int UInt32; typedef short Int16; typedef unsigned short UInt16; #define True ((Bool)1) #define False ((Bool)0) #ifndef __GNUC__ #define __inline__ /* */ #endif #ifndef BZ_NO_STDIO extern void BZ2_bz__AssertH__fail ( int errcode ); #define AssertH(cond,errcode) \ { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } #if BZ_DEBUG #define AssertD(cond,msg) \ { if (!(cond)) { \ fprintf ( stderr, \ "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ exit(1); \ }} #else #define AssertD(cond,msg) /* */ #endif #define VPrintf0(zf) \ fprintf(stderr,zf) #define VPrintf1(zf,za1) \ fprintf(stderr,zf,za1) #define VPrintf2(zf,za1,za2) \ fprintf(stderr,zf,za1,za2) #define VPrintf3(zf,za1,za2,za3) \ fprintf(stderr,zf,za1,za2,za3) #define VPrintf4(zf,za1,za2,za3,za4) \ fprintf(stderr,zf,za1,za2,za3,za4) #define VPrintf5(zf,za1,za2,za3,za4,za5) \ fprintf(stderr,zf,za1,za2,za3,za4,za5) #else extern void bz_internal_error ( int errcode ); #define AssertH(cond,errcode) \ { if (!(cond)) bz_internal_error ( errcode ); } #define AssertD(cond,msg) do { } while (0) #define VPrintf0(zf) do { } while (0) #define VPrintf1(zf,za1) do { } while (0) #define VPrintf2(zf,za1,za2) do { } while (0) #define VPrintf3(zf,za1,za2,za3) do { } while (0) #define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) #define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) #endif #define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) #define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) /*-- Header bytes. --*/ #define BZ_HDR_B 0x42 /* 'B' */ #define BZ_HDR_Z 0x5a /* 'Z' */ #define BZ_HDR_h 0x68 /* 'h' */ #define BZ_HDR_0 0x30 /* '0' */ /*-- Constants for the back end. --*/ #define BZ_MAX_ALPHA_SIZE 258 #define BZ_MAX_CODE_LEN 23 #define BZ_RUNA 0 #define BZ_RUNB 1 #define BZ_N_GROUPS 6 #define BZ_G_SIZE 50 #define BZ_N_ITERS 4 #define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) /*-- Stuff for randomising repetitive blocks. --*/ extern Int32 BZ2_rNums[512]; #define BZ_RAND_DECLS \ Int32 rNToGo; \ Int32 rTPos \ #define BZ_RAND_INIT_MASK \ s->rNToGo = 0; \ s->rTPos = 0 \ #define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) #define BZ_RAND_UPD_MASK \ if (s->rNToGo == 0) { \ s->rNToGo = BZ2_rNums[s->rTPos]; \ s->rTPos++; \ if (s->rTPos == 512) s->rTPos = 0; \ } \ s->rNToGo--; /*-- Stuff for doing CRCs. --*/ extern UInt32 BZ2_crc32Table[256]; #define BZ_INITIALISE_CRC(crcVar) \ { \ crcVar = 0xffffffffL; \ } #define BZ_FINALISE_CRC(crcVar) \ { \ crcVar = ~(crcVar); \ } #define BZ_UPDATE_CRC(crcVar,cha) \ { \ crcVar = (crcVar << 8) ^ \ BZ2_crc32Table[(crcVar >> 24) ^ \ ((UChar)cha)]; \ } /*-- States and modes for compression. --*/ #define BZ_M_IDLE 1 #define BZ_M_RUNNING 2 #define BZ_M_FLUSHING 3 #define BZ_M_FINISHING 4 #define BZ_S_OUTPUT 1 #define BZ_S_INPUT 2 #define BZ_N_RADIX 2 #define BZ_N_QSORT 12 #define BZ_N_SHELL 18 #define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) /*-- Structure holding all the compression-side stuff. --*/ typedef struct { /* pointer back to the struct bz_stream */ bz_stream* strm; /* mode this stream is in, and whether inputting */ /* or outputting data */ Int32 mode; Int32 state; /* remembers avail_in when flush/finish requested */ UInt32 avail_in_expect; /* for doing the block sorting */ UInt32* arr1; UInt32* arr2; UInt32* ftab; Int32 origPtr; /* aliases for arr1 and arr2 */ UInt32* ptr; UChar* block; UInt16* mtfv; UChar* zbits; /* for deciding when to use the fallback sorting algorithm */ Int32 workFactor; /* run-length-encoding of the input */ UInt32 state_in_ch; Int32 state_in_len; BZ_RAND_DECLS; /* input and output limits and current posns */ Int32 nblock; Int32 nblockMAX; Int32 numZ; Int32 state_out_pos; /* map of bytes used in block */ Int32 nInUse; Bool inUse[256]; UChar unseqToSeq[256]; /* the buffer for bit stream creation */ UInt32 bsBuff; Int32 bsLive; /* block and combined CRCs */ UInt32 blockCRC; UInt32 combinedCRC; /* misc administratium */ Int32 verbosity; Int32 blockNo; Int32 blockSize100k; /* stuff for coding the MTF values */ Int32 nMTF; Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; UChar selector [BZ_MAX_SELECTORS]; UChar selectorMtf[BZ_MAX_SELECTORS]; UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; /* second dimension: only 3 needed; 4 makes index calculations faster */ UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; } EState; /*-- externs for compression. --*/ extern void BZ2_blockSort ( EState* ); extern void BZ2_compressBlock ( EState*, Bool ); extern void BZ2_bsInitWrite ( EState* ); extern void BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); extern void BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); /*-- states for decompression. --*/ #define BZ_X_IDLE 1 #define BZ_X_OUTPUT 2 #define BZ_X_MAGIC_1 10 #define BZ_X_MAGIC_2 11 #define BZ_X_MAGIC_3 12 #define BZ_X_MAGIC_4 13 #define BZ_X_BLKHDR_1 14 #define BZ_X_BLKHDR_2 15 #define BZ_X_BLKHDR_3 16 #define BZ_X_BLKHDR_4 17 #define BZ_X_BLKHDR_5 18 #define BZ_X_BLKHDR_6 19 #define BZ_X_BCRC_1 20 #define BZ_X_BCRC_2 21 #define BZ_X_BCRC_3 22 #define BZ_X_BCRC_4 23 #define BZ_X_RANDBIT 24 #define BZ_X_ORIGPTR_1 25 #define BZ_X_ORIGPTR_2 26 #define BZ_X_ORIGPTR_3 27 #define BZ_X_MAPPING_1 28 #define BZ_X_MAPPING_2 29 #define BZ_X_SELECTOR_1 30 #define BZ_X_SELECTOR_2 31 #define BZ_X_SELECTOR_3 32 #define BZ_X_CODING_1 33 #define BZ_X_CODING_2 34 #define BZ_X_CODING_3 35 #define BZ_X_MTF_1 36 #define BZ_X_MTF_2 37 #define BZ_X_MTF_3 38 #define BZ_X_MTF_4 39 #define BZ_X_MTF_5 40 #define BZ_X_MTF_6 41 #define BZ_X_ENDHDR_2 42 #define BZ_X_ENDHDR_3 43 #define BZ_X_ENDHDR_4 44 #define BZ_X_ENDHDR_5 45 #define BZ_X_ENDHDR_6 46 #define BZ_X_CCRC_1 47 #define BZ_X_CCRC_2 48 #define BZ_X_CCRC_3 49 #define BZ_X_CCRC_4 50 /*-- Constants for the fast MTF decoder. --*/ #define MTFA_SIZE 4096 #define MTFL_SIZE 16 /*-- Structure holding all the decompression-side stuff. --*/ typedef struct { /* pointer back to the struct bz_stream */ bz_stream* strm; /* state indicator for this stream */ Int32 state; /* for doing the final run-length decoding */ UChar state_out_ch; Int32 state_out_len; Bool blockRandomised; BZ_RAND_DECLS; /* the buffer for bit stream reading */ UInt32 bsBuff; Int32 bsLive; /* misc administratium */ Int32 blockSize100k; Bool smallDecompress; Int32 currBlockNo; Int32 verbosity; /* for undoing the Burrows-Wheeler transform */ Int32 origPtr; UInt32 tPos; Int32 k0; Int32 unzftab[256]; Int32 nblock_used; Int32 cftab[257]; Int32 cftabCopy[257]; /* for undoing the Burrows-Wheeler transform (FAST) */ UInt32 *tt; /* for undoing the Burrows-Wheeler transform (SMALL) */ UInt16 *ll16; UChar *ll4; /* stored and calculated CRCs */ UInt32 storedBlockCRC; UInt32 storedCombinedCRC; UInt32 calculatedBlockCRC; UInt32 calculatedCombinedCRC; /* map of bytes used in block */ Int32 nInUse; Bool inUse[256]; Bool inUse16[16]; UChar seqToUnseq[256]; /* for decoding the MTF values */ UChar mtfa [MTFA_SIZE]; Int32 mtfbase[256 / MTFL_SIZE]; UChar selector [BZ_MAX_SELECTORS]; UChar selectorMtf[BZ_MAX_SELECTORS]; UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 minLens[BZ_N_GROUPS]; /* save area for scalars in the main decompress code */ Int32 save_i; Int32 save_j; Int32 save_t; Int32 save_alphaSize; Int32 save_nGroups; Int32 save_nSelectors; Int32 save_EOB; Int32 save_groupNo; Int32 save_groupPos; Int32 save_nextSym; Int32 save_nblockMAX; Int32 save_nblock; Int32 save_es; Int32 save_N; Int32 save_curr; Int32 save_zt; Int32 save_zn; Int32 save_zvec; Int32 save_zj; Int32 save_gSel; Int32 save_gMinlen; Int32* save_gLimit; Int32* save_gBase; Int32* save_gPerm; } DState; /*-- Macros for decompression. --*/ #define BZ_GET_FAST(cccc) \ /* c_tPos is unsigned, hence test < 0 is pointless. */ \ if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ s->tPos = s->tt[s->tPos]; \ cccc = (UChar)(s->tPos & 0xff); \ s->tPos >>= 8; #define BZ_GET_FAST_C(cccc) \ /* c_tPos is unsigned, hence test < 0 is pointless. */ \ if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ c_tPos = c_tt[c_tPos]; \ cccc = (UChar)(c_tPos & 0xff); \ c_tPos >>= 8; #define SET_LL4(i,n) \ { if (((i) & 0x1) == 0) \ s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ } #define GET_LL4(i) \ ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) #define SET_LL(i,n) \ { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ SET_LL4(i, n >> 16); \ } #define GET_LL(i) \ (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) #define BZ_GET_SMALL(cccc) \ /* c_tPos is unsigned, hence test < 0 is pointless. */ \ if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ s->tPos = GET_LL(s->tPos); /*-- externs for decompression. --*/ extern Int32 BZ2_indexIntoF ( Int32, Int32* ); extern Int32 BZ2_decompress ( DState* ); extern void BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, Int32, Int32, Int32 ); #endif /*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ #ifdef BZ_NO_STDIO #ifndef NULL #define NULL 0 #endif #endif /*-------------------------------------------------------------*/ /*--- end bzlib_private.h ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/compress.c0000644000000000000000000005010207346545000013636 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Compression machinery (not incl block sorting) ---*/ /*--- compress.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ /* CHANGES 0.9.0 -- original version. 0.9.0a/b -- no changes in this file. 0.9.0c -- changed setting of nGroups in sendMTFValues() so as to do a bit better on small files */ #include "bzlib_private.h" /*---------------------------------------------------*/ /*--- Bit stream I/O ---*/ /*---------------------------------------------------*/ /*---------------------------------------------------*/ void BZ2_bsInitWrite ( EState* s ) { s->bsLive = 0; s->bsBuff = 0; } /*---------------------------------------------------*/ static void bsFinishWrite ( EState* s ) { while (s->bsLive > 0) { s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); s->numZ++; s->bsBuff <<= 8; s->bsLive -= 8; } } /*---------------------------------------------------*/ #define bsNEEDW(nz) \ { \ while (s->bsLive >= 8) { \ s->zbits[s->numZ] \ = (UChar)(s->bsBuff >> 24); \ s->numZ++; \ s->bsBuff <<= 8; \ s->bsLive -= 8; \ } \ } /*---------------------------------------------------*/ static __inline__ void bsW ( EState* s, Int32 n, UInt32 v ) { bsNEEDW ( n ); s->bsBuff |= (v << (32 - s->bsLive - n)); s->bsLive += n; } /*---------------------------------------------------*/ static void bsPutUInt32 ( EState* s, UInt32 u ) { bsW ( s, 8, (u >> 24) & 0xffL ); bsW ( s, 8, (u >> 16) & 0xffL ); bsW ( s, 8, (u >> 8) & 0xffL ); bsW ( s, 8, u & 0xffL ); } /*---------------------------------------------------*/ static void bsPutUChar ( EState* s, UChar c ) { bsW( s, 8, (UInt32)c ); } /*---------------------------------------------------*/ /*--- The back end proper ---*/ /*---------------------------------------------------*/ /*---------------------------------------------------*/ static void makeMaps_e ( EState* s ) { Int32 i; s->nInUse = 0; for (i = 0; i < 256; i++) if (s->inUse[i]) { s->unseqToSeq[i] = s->nInUse; s->nInUse++; } } /*---------------------------------------------------*/ static void generateMTFValues ( EState* s ) { UChar yy[256]; Int32 i, j; Int32 zPend; Int32 wr; Int32 EOB; /* After sorting (eg, here), s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, and ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] holds the original block data. The first thing to do is generate the MTF values, and put them in ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. Because there are strictly fewer or equal MTF values than block values, ptr values in this area are overwritten with MTF values only when they are no longer needed. The final compressed bitstream is generated into the area starting at (UChar*) (&((UChar*)s->arr2)[s->nblock]) These storage aliases are set up in bzCompressInit(), except for the last one, which is arranged in compressBlock(). */ UInt32* ptr = s->ptr; UChar* block = s->block; UInt16* mtfv = s->mtfv; makeMaps_e ( s ); EOB = s->nInUse+1; for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; wr = 0; zPend = 0; for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; for (i = 0; i < s->nblock; i++) { UChar ll_i; AssertD ( wr <= i, "generateMTFValues(1)" ); j = ptr[i]-1; if (j < 0) j += s->nblock; ll_i = s->unseqToSeq[block[j]]; AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); if (yy[0] == ll_i) { zPend++; } else { if (zPend > 0) { zPend--; while (True) { if (zPend & 1) { mtfv[wr] = BZ_RUNB; wr++; s->mtfFreq[BZ_RUNB]++; } else { mtfv[wr] = BZ_RUNA; wr++; s->mtfFreq[BZ_RUNA]++; } if (zPend < 2) break; zPend = (zPend - 2) / 2; }; zPend = 0; } { register UChar rtmp; register UChar* ryy_j; register UChar rll_i; rtmp = yy[1]; yy[1] = yy[0]; ryy_j = &(yy[1]); rll_i = ll_i; while ( rll_i != rtmp ) { register UChar rtmp2; ryy_j++; rtmp2 = rtmp; rtmp = *ryy_j; *ryy_j = rtmp2; }; yy[0] = rtmp; j = ryy_j - &(yy[0]); mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; } } } if (zPend > 0) { zPend--; while (True) { if (zPend & 1) { mtfv[wr] = BZ_RUNB; wr++; s->mtfFreq[BZ_RUNB]++; } else { mtfv[wr] = BZ_RUNA; wr++; s->mtfFreq[BZ_RUNA]++; } if (zPend < 2) break; zPend = (zPend - 2) / 2; }; zPend = 0; } mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; s->nMTF = wr; } /*---------------------------------------------------*/ #define BZ_LESSER_ICOST 0 #define BZ_GREATER_ICOST 15 static void sendMTFValues ( EState* s ) { Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; Int32 nGroups, nBytes; /*-- UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; is a global since the decoder also needs it. Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; are also globals only used in this proc. Made global to keep stack frame size small. --*/ UInt16 cost[BZ_N_GROUPS]; Int32 fave[BZ_N_GROUPS]; UInt16* mtfv = s->mtfv; if (s->verbosity >= 3) VPrintf3( " %d in block, %d after MTF & 1-2 coding, " "%d+2 syms in use\n", s->nblock, s->nMTF, s->nInUse ); alphaSize = s->nInUse+2; for (t = 0; t < BZ_N_GROUPS; t++) for (v = 0; v < alphaSize; v++) s->len[t][v] = BZ_GREATER_ICOST; /*--- Decide how many coding tables to use ---*/ AssertH ( s->nMTF > 0, 3001 ); if (s->nMTF < 200) nGroups = 2; else if (s->nMTF < 600) nGroups = 3; else if (s->nMTF < 1200) nGroups = 4; else if (s->nMTF < 2400) nGroups = 5; else nGroups = 6; /*--- Generate an initial set of coding tables ---*/ { Int32 nPart, remF, tFreq, aFreq; nPart = nGroups; remF = s->nMTF; gs = 0; while (nPart > 0) { tFreq = remF / nPart; ge = gs-1; aFreq = 0; while (aFreq < tFreq && ge < alphaSize-1) { ge++; aFreq += s->mtfFreq[ge]; } if (ge > gs && nPart != nGroups && nPart != 1 && ((nGroups-nPart) % 2 == 1)) { aFreq -= s->mtfFreq[ge]; ge--; } if (s->verbosity >= 3) VPrintf5( " initial group %d, [%d .. %d], " "has %d syms (%4.1f%%)\n", nPart, gs, ge, aFreq, (100.0 * (float)aFreq) / (float)(s->nMTF) ); for (v = 0; v < alphaSize; v++) if (v >= gs && v <= ge) s->len[nPart-1][v] = BZ_LESSER_ICOST; else s->len[nPart-1][v] = BZ_GREATER_ICOST; nPart--; gs = ge+1; remF -= aFreq; } } /*--- Iterate up to BZ_N_ITERS times to improve the tables. ---*/ for (iter = 0; iter < BZ_N_ITERS; iter++) { for (t = 0; t < nGroups; t++) fave[t] = 0; for (t = 0; t < nGroups; t++) for (v = 0; v < alphaSize; v++) s->rfreq[t][v] = 0; /*--- Set up an auxiliary length table which is used to fast-track the common case (nGroups == 6). ---*/ if (nGroups == 6) { for (v = 0; v < alphaSize; v++) { s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; } } nSelectors = 0; totc = 0; gs = 0; while (True) { /*--- Set group start & end marks. --*/ if (gs >= s->nMTF) break; ge = gs + BZ_G_SIZE - 1; if (ge >= s->nMTF) ge = s->nMTF-1; /*-- Calculate the cost of this group as coded by each of the coding tables. --*/ for (t = 0; t < nGroups; t++) cost[t] = 0; if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ register UInt32 cost01, cost23, cost45; register UInt16 icv; cost01 = cost23 = cost45 = 0; # define BZ_ITER(nn) \ icv = mtfv[gs+(nn)]; \ cost01 += s->len_pack[icv][0]; \ cost23 += s->len_pack[icv][1]; \ cost45 += s->len_pack[icv][2]; \ BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); # undef BZ_ITER cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; } else { /*--- slow version which correctly handles all situations ---*/ for (i = gs; i <= ge; i++) { UInt16 icv = mtfv[i]; for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; } } /*-- Find the coding table which is best for this group, and record its identity in the selector table. --*/ bc = 999999999; bt = -1; for (t = 0; t < nGroups; t++) if (cost[t] < bc) { bc = cost[t]; bt = t; }; totc += bc; fave[bt]++; s->selector[nSelectors] = bt; nSelectors++; /*-- Increment the symbol frequencies for the selected table. --*/ if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ # define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); # undef BZ_ITUR } else { /*--- slow version which correctly handles all situations ---*/ for (i = gs; i <= ge; i++) s->rfreq[bt][ mtfv[i] ]++; } gs = ge+1; } if (s->verbosity >= 3) { VPrintf2 ( " pass %d: size is %d, grp uses are ", iter+1, totc/8 ); for (t = 0; t < nGroups; t++) VPrintf1 ( "%d ", fave[t] ); VPrintf0 ( "\n" ); } /*-- Recompute the tables based on the accumulated frequencies. --*/ /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See comment in huffman.c for details. */ for (t = 0; t < nGroups; t++) BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/ ); } AssertH( nGroups < 8, 3002 ); AssertH( nSelectors < 32768 && nSelectors <= BZ_MAX_SELECTORS, 3003 ); /*--- Compute MTF values for the selectors. ---*/ { UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; for (i = 0; i < nGroups; i++) pos[i] = i; for (i = 0; i < nSelectors; i++) { ll_i = s->selector[i]; j = 0; tmp = pos[j]; while ( ll_i != tmp ) { j++; tmp2 = tmp; tmp = pos[j]; pos[j] = tmp2; }; pos[0] = tmp; s->selectorMtf[i] = j; } }; /*--- Assign actual codes for the tables. --*/ for (t = 0; t < nGroups; t++) { minLen = 32; maxLen = 0; for (i = 0; i < alphaSize; i++) { if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; if (s->len[t][i] < minLen) minLen = s->len[t][i]; } AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); AssertH ( !(minLen < 1), 3005 ); BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize ); } /*--- Transmit the mapping table. ---*/ { Bool inUse16[16]; for (i = 0; i < 16; i++) { inUse16[i] = False; for (j = 0; j < 16; j++) if (s->inUse[i * 16 + j]) inUse16[i] = True; } nBytes = s->numZ; for (i = 0; i < 16; i++) if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); for (i = 0; i < 16; i++) if (inUse16[i]) for (j = 0; j < 16; j++) { if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); } if (s->verbosity >= 3) VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); } /*--- Now the selectors. ---*/ nBytes = s->numZ; bsW ( s, 3, nGroups ); bsW ( s, 15, nSelectors ); for (i = 0; i < nSelectors; i++) { for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); bsW(s,1,0); } if (s->verbosity >= 3) VPrintf1( "selectors %d, ", s->numZ-nBytes ); /*--- Now the coding tables. ---*/ nBytes = s->numZ; for (t = 0; t < nGroups; t++) { Int32 curr = s->len[t][0]; bsW ( s, 5, curr ); for (i = 0; i < alphaSize; i++) { while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; bsW ( s, 1, 0 ); } } if (s->verbosity >= 3) VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); /*--- And finally, the block data proper ---*/ nBytes = s->numZ; selCtr = 0; gs = 0; while (True) { if (gs >= s->nMTF) break; ge = gs + BZ_G_SIZE - 1; if (ge >= s->nMTF) ge = s->nMTF-1; AssertH ( s->selector[selCtr] < nGroups, 3006 ); if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ UInt16 mtfv_i; UChar* s_len_sel_selCtr = &(s->len[s->selector[selCtr]][0]); Int32* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); # define BZ_ITAH(nn) \ mtfv_i = mtfv[gs+(nn)]; \ bsW ( s, \ s_len_sel_selCtr[mtfv_i], \ s_code_sel_selCtr[mtfv_i] ) BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); # undef BZ_ITAH } else { /*--- slow version which correctly handles all situations ---*/ for (i = gs; i <= ge; i++) { bsW ( s, s->len [s->selector[selCtr]] [mtfv[i]], s->code [s->selector[selCtr]] [mtfv[i]] ); } } gs = ge+1; selCtr++; } AssertH( selCtr == nSelectors, 3007 ); if (s->verbosity >= 3) VPrintf1( "codes %d\n", s->numZ-nBytes ); } /*---------------------------------------------------*/ void BZ2_compressBlock ( EState* s, Bool is_last_block ) { if (s->nblock > 0) { BZ_FINALISE_CRC ( s->blockCRC ); s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); s->combinedCRC ^= s->blockCRC; if (s->blockNo > 1) s->numZ = 0; if (s->verbosity >= 2) VPrintf4( " block %d: crc = 0x%08x, " "combined CRC = 0x%08x, size = %d\n", s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); BZ2_blockSort ( s ); } s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); /*-- If this is the first block, create the stream header. --*/ if (s->blockNo == 1) { BZ2_bsInitWrite ( s ); bsPutUChar ( s, BZ_HDR_B ); bsPutUChar ( s, BZ_HDR_Z ); bsPutUChar ( s, BZ_HDR_h ); bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); } if (s->nblock > 0) { bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); /*-- Now the block's CRC, so it is in a known place. --*/ bsPutUInt32 ( s, s->blockCRC ); /*-- Now a single bit indicating (non-)randomisation. As of version 0.9.5, we use a better sorting algorithm which makes randomisation unnecessary. So always set the randomised bit to 'no'. Of course, the decoder still needs to be able to handle randomised blocks so as to maintain backwards compatibility with older versions of bzip2. --*/ bsW(s,1,0); bsW ( s, 24, s->origPtr ); generateMTFValues ( s ); sendMTFValues ( s ); } /*-- If this is the last block, add the stream trailer. --*/ if (is_last_block) { bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); bsPutUInt32 ( s, s->combinedCRC ); if (s->verbosity >= 2) VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); bsFinishWrite ( s ); } } /*-------------------------------------------------------------*/ /*--- end compress.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/crctable.c0000644000000000000000000001131507346545000013565 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Table for doing CRCs ---*/ /*--- crctable.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #include "bzlib_private.h" /*-- I think this is an implementation of the AUTODIN-II, Ethernet & FDDI 32-bit CRC standard. Vaguely derived from code by Rob Warnock, in Section 51 of the comp.compression FAQ. --*/ UInt32 BZ2_crc32Table[256] = { /*-- Ugly, innit? --*/ 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L }; /*-------------------------------------------------------------*/ /*--- end crctable.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/decompress.c0000644000000000000000000005141207346545000014154 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Decompression machinery ---*/ /*--- decompress.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #include "bzlib_private.h" /*---------------------------------------------------*/ static void makeMaps_d ( DState* s ) { Int32 i; s->nInUse = 0; for (i = 0; i < 256; i++) if (s->inUse[i]) { s->seqToUnseq[s->nInUse] = i; s->nInUse++; } } /*---------------------------------------------------*/ #define RETURN(rrr) \ { retVal = rrr; goto save_state_and_return; }; #define GET_BITS(lll,vvv,nnn) \ case lll: s->state = lll; \ while (True) { \ if (s->bsLive >= nnn) { \ UInt32 v; \ v = (s->bsBuff >> \ (s->bsLive-nnn)) & ((1 << nnn)-1); \ s->bsLive -= nnn; \ vvv = v; \ break; \ } \ if (s->strm->avail_in == 0) RETURN(BZ_OK); \ s->bsBuff \ = (s->bsBuff << 8) | \ ((UInt32) \ (*((UChar*)(s->strm->next_in)))); \ s->bsLive += 8; \ s->strm->next_in++; \ s->strm->avail_in--; \ s->strm->total_in_lo32++; \ if (s->strm->total_in_lo32 == 0) \ s->strm->total_in_hi32++; \ } #define GET_UCHAR(lll,uuu) \ GET_BITS(lll,uuu,8) #define GET_BIT(lll,uuu) \ GET_BITS(lll,uuu,1) /*---------------------------------------------------*/ #define GET_MTF_VAL(label1,label2,lval) \ { \ if (groupPos == 0) { \ groupNo++; \ if (groupNo >= nSelectors) \ RETURN(BZ_DATA_ERROR); \ groupPos = BZ_G_SIZE; \ gSel = s->selector[groupNo]; \ gMinlen = s->minLens[gSel]; \ gLimit = &(s->limit[gSel][0]); \ gPerm = &(s->perm[gSel][0]); \ gBase = &(s->base[gSel][0]); \ } \ groupPos--; \ zn = gMinlen; \ GET_BITS(label1, zvec, zn); \ while (1) { \ if (zn > 20 /* the longest code */) \ RETURN(BZ_DATA_ERROR); \ if (zvec <= gLimit[zn]) break; \ zn++; \ GET_BIT(label2, zj); \ zvec = (zvec << 1) | zj; \ }; \ if (zvec - gBase[zn] < 0 \ || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ RETURN(BZ_DATA_ERROR); \ lval = gPerm[zvec - gBase[zn]]; \ } /*---------------------------------------------------*/ Int32 BZ2_decompress ( DState* s ) { UChar uc; Int32 retVal; Int32 minLen, maxLen; bz_stream* strm = s->strm; /* stuff that needs to be saved/restored */ Int32 i; Int32 j; Int32 t; Int32 alphaSize; Int32 nGroups; Int32 nSelectors; Int32 EOB; Int32 groupNo; Int32 groupPos; Int32 nextSym; Int32 nblockMAX; Int32 nblock; Int32 es; Int32 N; Int32 curr; Int32 zt; Int32 zn; Int32 zvec; Int32 zj; Int32 gSel; Int32 gMinlen; Int32* gLimit; Int32* gBase; Int32* gPerm; if (s->state == BZ_X_MAGIC_1) { /*initialise the save area*/ s->save_i = 0; s->save_j = 0; s->save_t = 0; s->save_alphaSize = 0; s->save_nGroups = 0; s->save_nSelectors = 0; s->save_EOB = 0; s->save_groupNo = 0; s->save_groupPos = 0; s->save_nextSym = 0; s->save_nblockMAX = 0; s->save_nblock = 0; s->save_es = 0; s->save_N = 0; s->save_curr = 0; s->save_zt = 0; s->save_zn = 0; s->save_zvec = 0; s->save_zj = 0; s->save_gSel = 0; s->save_gMinlen = 0; s->save_gLimit = NULL; s->save_gBase = NULL; s->save_gPerm = NULL; } /*restore from the save area*/ i = s->save_i; j = s->save_j; t = s->save_t; alphaSize = s->save_alphaSize; nGroups = s->save_nGroups; nSelectors = s->save_nSelectors; EOB = s->save_EOB; groupNo = s->save_groupNo; groupPos = s->save_groupPos; nextSym = s->save_nextSym; nblockMAX = s->save_nblockMAX; nblock = s->save_nblock; es = s->save_es; N = s->save_N; curr = s->save_curr; zt = s->save_zt; zn = s->save_zn; zvec = s->save_zvec; zj = s->save_zj; gSel = s->save_gSel; gMinlen = s->save_gMinlen; gLimit = s->save_gLimit; gBase = s->save_gBase; gPerm = s->save_gPerm; retVal = BZ_OK; switch (s->state) { GET_UCHAR(BZ_X_MAGIC_1, uc); if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); GET_UCHAR(BZ_X_MAGIC_2, uc); if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); GET_UCHAR(BZ_X_MAGIC_3, uc) if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) if (s->blockSize100k < (BZ_HDR_0 + 1) || s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); s->blockSize100k -= BZ_HDR_0; if (s->smallDecompress) { s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); s->ll4 = BZALLOC( ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) ); if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); } else { s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); if (s->tt == NULL) RETURN(BZ_MEM_ERROR); } GET_UCHAR(BZ_X_BLKHDR_1, uc); if (uc == 0x17) goto endhdr_2; if (uc != 0x31) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_BLKHDR_2, uc); if (uc != 0x41) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_BLKHDR_3, uc); if (uc != 0x59) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_BLKHDR_4, uc); if (uc != 0x26) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_BLKHDR_5, uc); if (uc != 0x53) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_BLKHDR_6, uc); if (uc != 0x59) RETURN(BZ_DATA_ERROR); s->currBlockNo++; if (s->verbosity >= 2) VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); s->storedBlockCRC = 0; GET_UCHAR(BZ_X_BCRC_1, uc); s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); GET_UCHAR(BZ_X_BCRC_2, uc); s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); GET_UCHAR(BZ_X_BCRC_3, uc); s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); GET_UCHAR(BZ_X_BCRC_4, uc); s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); s->origPtr = 0; GET_UCHAR(BZ_X_ORIGPTR_1, uc); s->origPtr = (s->origPtr << 8) | ((Int32)uc); GET_UCHAR(BZ_X_ORIGPTR_2, uc); s->origPtr = (s->origPtr << 8) | ((Int32)uc); GET_UCHAR(BZ_X_ORIGPTR_3, uc); s->origPtr = (s->origPtr << 8) | ((Int32)uc); if (s->origPtr < 0) RETURN(BZ_DATA_ERROR); if (s->origPtr > 10 + 100000*s->blockSize100k) RETURN(BZ_DATA_ERROR); /*--- Receive the mapping table ---*/ for (i = 0; i < 16; i++) { GET_BIT(BZ_X_MAPPING_1, uc); if (uc == 1) s->inUse16[i] = True; else s->inUse16[i] = False; } for (i = 0; i < 256; i++) s->inUse[i] = False; for (i = 0; i < 16; i++) if (s->inUse16[i]) for (j = 0; j < 16; j++) { GET_BIT(BZ_X_MAPPING_2, uc); if (uc == 1) s->inUse[i * 16 + j] = True; } makeMaps_d ( s ); if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); alphaSize = s->nInUse+2; /*--- Now the selectors ---*/ GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); if (nGroups < 2 || nGroups > BZ_N_GROUPS) RETURN(BZ_DATA_ERROR); GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); if (nSelectors < 1) RETURN(BZ_DATA_ERROR); for (i = 0; i < nSelectors; i++) { j = 0; while (True) { GET_BIT(BZ_X_SELECTOR_3, uc); if (uc == 0) break; j++; if (j >= nGroups) RETURN(BZ_DATA_ERROR); } /* Having more than BZ_MAX_SELECTORS doesn't make much sense since they will never be used, but some implementations might "round up" the number of selectors, so just ignore those. */ if (i < BZ_MAX_SELECTORS) s->selectorMtf[i] = j; } if (nSelectors > BZ_MAX_SELECTORS) nSelectors = BZ_MAX_SELECTORS; /*--- Undo the MTF values for the selectors. ---*/ { UChar pos[BZ_N_GROUPS], tmp, v; for (v = 0; v < nGroups; v++) pos[v] = v; for (i = 0; i < nSelectors; i++) { v = s->selectorMtf[i]; tmp = pos[v]; while (v > 0) { pos[v] = pos[v-1]; v--; } pos[0] = tmp; s->selector[i] = tmp; } } /*--- Now the coding tables ---*/ for (t = 0; t < nGroups; t++) { GET_BITS(BZ_X_CODING_1, curr, 5); for (i = 0; i < alphaSize; i++) { while (True) { if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); GET_BIT(BZ_X_CODING_2, uc); if (uc == 0) break; GET_BIT(BZ_X_CODING_3, uc); if (uc == 0) curr++; else curr--; } s->len[t][i] = curr; } } /*--- Create the Huffman decoding tables ---*/ for (t = 0; t < nGroups; t++) { minLen = 32; maxLen = 0; for (i = 0; i < alphaSize; i++) { if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; if (s->len[t][i] < minLen) minLen = s->len[t][i]; } BZ2_hbCreateDecodeTables ( &(s->limit[t][0]), &(s->base[t][0]), &(s->perm[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize ); s->minLens[t] = minLen; } /*--- Now the MTF values ---*/ EOB = s->nInUse+1; nblockMAX = 100000 * s->blockSize100k; groupNo = -1; groupPos = 0; for (i = 0; i <= 255; i++) s->unzftab[i] = 0; /*-- MTF init --*/ { Int32 ii, jj, kk; kk = MTFA_SIZE-1; for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { for (jj = MTFL_SIZE-1; jj >= 0; jj--) { s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); kk--; } s->mtfbase[ii] = kk + 1; } } /*-- end MTF init --*/ nblock = 0; GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); while (True) { if (nextSym == EOB) break; if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { es = -1; N = 1; do { /* Check that N doesn't get too big, so that es doesn't go negative. The maximum value that can be RUNA/RUNB encoded is equal to the block size (post the initial RLE), viz, 900k, so bounding N at 2 million should guard against overflow without rejecting any legitimate inputs. */ if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR); if (nextSym == BZ_RUNA) es = es + (0+1) * N; else if (nextSym == BZ_RUNB) es = es + (1+1) * N; N = N * 2; GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); } while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); es++; uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; s->unzftab[uc] += es; if (s->smallDecompress) while (es > 0) { if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); s->ll16[nblock] = (UInt16)uc; nblock++; es--; } else while (es > 0) { if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); s->tt[nblock] = (UInt32)uc; nblock++; es--; }; continue; } else { if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); /*-- uc = MTF ( nextSym-1 ) --*/ { Int32 ii, jj, kk, pp, lno, off; UInt32 nn; nn = (UInt32)(nextSym - 1); if (nn < MTFL_SIZE) { /* avoid general-case expense */ pp = s->mtfbase[0]; uc = s->mtfa[pp+nn]; while (nn > 3) { Int32 z = pp+nn; s->mtfa[(z) ] = s->mtfa[(z)-1]; s->mtfa[(z)-1] = s->mtfa[(z)-2]; s->mtfa[(z)-2] = s->mtfa[(z)-3]; s->mtfa[(z)-3] = s->mtfa[(z)-4]; nn -= 4; } while (nn > 0) { s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; }; s->mtfa[pp] = uc; } else { /* general case */ lno = nn / MTFL_SIZE; off = nn % MTFL_SIZE; pp = s->mtfbase[lno] + off; uc = s->mtfa[pp]; while (pp > s->mtfbase[lno]) { s->mtfa[pp] = s->mtfa[pp-1]; pp--; }; s->mtfbase[lno]++; while (lno > 0) { s->mtfbase[lno]--; s->mtfa[s->mtfbase[lno]] = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; lno--; } s->mtfbase[0]--; s->mtfa[s->mtfbase[0]] = uc; if (s->mtfbase[0] == 0) { kk = MTFA_SIZE-1; for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { for (jj = MTFL_SIZE-1; jj >= 0; jj--) { s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; kk--; } s->mtfbase[ii] = kk + 1; } } } } /*-- end uc = MTF ( nextSym-1 ) --*/ s->unzftab[s->seqToUnseq[uc]]++; if (s->smallDecompress) s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); nblock++; GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); continue; } } /* Now we know what nblock is, we can do a better sanity check on s->origPtr. */ if (s->origPtr < 0 || s->origPtr >= nblock) RETURN(BZ_DATA_ERROR); /*-- Set up cftab to facilitate generation of T^(-1) --*/ /* Check: unzftab entries in range. */ for (i = 0; i <= 255; i++) { if (s->unzftab[i] < 0 || s->unzftab[i] > nblock) RETURN(BZ_DATA_ERROR); } /* Actually generate cftab. */ s->cftab[0] = 0; for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; /* Check: cftab entries in range. */ for (i = 0; i <= 256; i++) { if (s->cftab[i] < 0 || s->cftab[i] > nblock) { /* s->cftab[i] can legitimately be == nblock */ RETURN(BZ_DATA_ERROR); } } /* Check: cftab entries non-descending. */ for (i = 1; i <= 256; i++) { if (s->cftab[i-1] > s->cftab[i]) { RETURN(BZ_DATA_ERROR); } } s->state_out_len = 0; s->state_out_ch = 0; BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); s->state = BZ_X_OUTPUT; if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); if (s->smallDecompress) { /*-- Make a copy of cftab, used in generation of T --*/ for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; /*-- compute the T vector --*/ for (i = 0; i < nblock; i++) { uc = (UChar)(s->ll16[i]); SET_LL(i, s->cftabCopy[uc]); s->cftabCopy[uc]++; } /*-- Compute T^(-1) by pointer reversal on T --*/ i = s->origPtr; j = GET_LL(i); do { Int32 tmp = GET_LL(j); SET_LL(j, i); i = j; j = tmp; } while (i != s->origPtr); s->tPos = s->origPtr; s->nblock_used = 0; if (s->blockRandomised) { BZ_RAND_INIT_MASK; BZ_GET_SMALL(s->k0); s->nblock_used++; BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; } else { BZ_GET_SMALL(s->k0); s->nblock_used++; } } else { /*-- compute the T^(-1) vector --*/ for (i = 0; i < nblock; i++) { uc = (UChar)(s->tt[i] & 0xff); s->tt[s->cftab[uc]] |= (i << 8); s->cftab[uc]++; } s->tPos = s->tt[s->origPtr] >> 8; s->nblock_used = 0; if (s->blockRandomised) { BZ_RAND_INIT_MASK; BZ_GET_FAST(s->k0); s->nblock_used++; BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; } else { BZ_GET_FAST(s->k0); s->nblock_used++; } } RETURN(BZ_OK); endhdr_2: GET_UCHAR(BZ_X_ENDHDR_2, uc); if (uc != 0x72) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_ENDHDR_3, uc); if (uc != 0x45) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_ENDHDR_4, uc); if (uc != 0x38) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_ENDHDR_5, uc); if (uc != 0x50) RETURN(BZ_DATA_ERROR); GET_UCHAR(BZ_X_ENDHDR_6, uc); if (uc != 0x90) RETURN(BZ_DATA_ERROR); s->storedCombinedCRC = 0; GET_UCHAR(BZ_X_CCRC_1, uc); s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); GET_UCHAR(BZ_X_CCRC_2, uc); s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); GET_UCHAR(BZ_X_CCRC_3, uc); s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); GET_UCHAR(BZ_X_CCRC_4, uc); s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); s->state = BZ_X_IDLE; RETURN(BZ_STREAM_END); default: AssertH ( False, 4001 ); } AssertH ( False, 4002 ); save_state_and_return: s->save_i = i; s->save_j = j; s->save_t = t; s->save_alphaSize = alphaSize; s->save_nGroups = nGroups; s->save_nSelectors = nSelectors; s->save_EOB = EOB; s->save_groupNo = groupNo; s->save_groupPos = groupPos; s->save_nextSym = nextSym; s->save_nblockMAX = nblockMAX; s->save_nblock = nblock; s->save_es = es; s->save_N = N; s->save_curr = curr; s->save_zt = zt; s->save_zn = zn; s->save_zvec = zvec; s->save_zj = zj; s->save_gSel = gSel; s->save_gMinlen = gMinlen; s->save_gLimit = gLimit; s->save_gBase = gBase; s->save_gPerm = gPerm; return retVal; } /*-------------------------------------------------------------*/ /*--- end decompress.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/huffman.c0000644000000000000000000001551207346545000013435 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Huffman coding low-level stuff ---*/ /*--- huffman.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #include "bzlib_private.h" /*---------------------------------------------------*/ #define WEIGHTOF(zz0) ((zz0) & 0xffffff00) #define DEPTHOF(zz1) ((zz1) & 0x000000ff) #define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) #define ADDWEIGHTS(zw1,zw2) \ (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) #define UPHEAP(z) \ { \ Int32 zz, tmp; \ zz = z; tmp = heap[zz]; \ while (weight[tmp] < weight[heap[zz >> 1]]) { \ heap[zz] = heap[zz >> 1]; \ zz >>= 1; \ } \ heap[zz] = tmp; \ } #define DOWNHEAP(z) \ { \ Int32 zz, yy, tmp; \ zz = z; tmp = heap[zz]; \ while (True) { \ yy = zz << 1; \ if (yy > nHeap) break; \ if (yy < nHeap && \ weight[heap[yy+1]] < weight[heap[yy]]) \ yy++; \ if (weight[tmp] < weight[heap[yy]]) break; \ heap[zz] = heap[yy]; \ zz = yy; \ } \ heap[zz] = tmp; \ } /*---------------------------------------------------*/ void BZ2_hbMakeCodeLengths ( UChar *len, Int32 *freq, Int32 alphaSize, Int32 maxLen ) { /*-- Nodes and heap entries run from 1. Entry 0 for both the heap and nodes is a sentinel. --*/ Int32 nNodes, nHeap, n1, n2, i, j, k; Bool tooLong; Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; for (i = 0; i < alphaSize; i++) weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; while (True) { nNodes = alphaSize; nHeap = 0; heap[0] = 0; weight[0] = 0; parent[0] = -2; for (i = 1; i <= alphaSize; i++) { parent[i] = -1; nHeap++; heap[nHeap] = i; UPHEAP(nHeap); } AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); while (nHeap > 1) { n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); nNodes++; parent[n1] = parent[n2] = nNodes; weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); parent[nNodes] = -1; nHeap++; heap[nHeap] = nNodes; UPHEAP(nHeap); } AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); tooLong = False; for (i = 1; i <= alphaSize; i++) { j = 0; k = i; while (parent[k] >= 0) { k = parent[k]; j++; } len[i-1] = j; if (j > maxLen) tooLong = True; } if (! tooLong) break; /* 17 Oct 04: keep-going condition for the following loop used to be 'i < alphaSize', which missed the last element, theoretically leading to the possibility of the compressor looping. However, this count-scaling step is only needed if one of the generated Huffman code words is longer than maxLen, which up to and including version 1.0.2 was 20 bits, which is extremely unlikely. In version 1.0.3 maxLen was changed to 17 bits, which has minimal effect on compression ratio, but does mean this scaling step is used from time to time, enough to verify that it works. This means that bzip2-1.0.3 and later will only produce Huffman codes with a maximum length of 17 bits. However, in order to preserve backwards compatibility with bitstreams produced by versions pre-1.0.3, the decompressor must still handle lengths of up to 20. */ for (i = 1; i <= alphaSize; i++) { j = weight[i] >> 8; j = 1 + (j / 2); weight[i] = j << 8; } } } /*---------------------------------------------------*/ void BZ2_hbAssignCodes ( Int32 *code, UChar *length, Int32 minLen, Int32 maxLen, Int32 alphaSize ) { Int32 n, vec, i; vec = 0; for (n = minLen; n <= maxLen; n++) { for (i = 0; i < alphaSize; i++) if (length[i] == n) { code[i] = vec; vec++; }; vec <<= 1; } } /*---------------------------------------------------*/ void BZ2_hbCreateDecodeTables ( Int32 *limit, Int32 *base, Int32 *perm, UChar *length, Int32 minLen, Int32 maxLen, Int32 alphaSize ) { Int32 pp, i, j, vec; pp = 0; for (i = minLen; i <= maxLen; i++) for (j = 0; j < alphaSize; j++) if (length[j] == i) { perm[pp] = j; pp++; }; for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; for (i = 0; i < alphaSize; i++) base[length[i]+1]++; for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; vec = 0; for (i = minLen; i <= maxLen; i++) { vec += (base[i+1] - base[i]); limit[i] = vec-1; vec <<= 1; } for (i = minLen + 1; i <= maxLen; i++) base[i] = ((limit[i-1] + 1) << 1) - base[i]; } /*-------------------------------------------------------------*/ /*--- end huffman.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/cbits/randtable.c0000644000000000000000000000741707346545000013752 0ustar0000000000000000 /*-------------------------------------------------------------*/ /*--- Table for randomising repetitive blocks ---*/ /*--- randtable.c ---*/ /*-------------------------------------------------------------*/ /* ------------------------------------------------------------------ This file is part of bzip2/libbzip2, a program and library for lossless, block-sorting data compression. bzip2/libbzip2 version 1.0.8 of 13 July 2019 Copyright (C) 1996-2019 Julian Seward Please read the WARNING, DISCLAIMER and PATENTS sections in the README file. This program is released under the terms of the license contained in the file LICENSE. ------------------------------------------------------------------ */ #include "bzlib_private.h" /*---------------------------------------------*/ Int32 BZ2_rNums[512] = { 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 936, 638 }; /*-------------------------------------------------------------*/ /*--- end randtable.c ---*/ /*-------------------------------------------------------------*/ bz2-1.0.0.1/mem/0000755000000000000000000000000007346545000011313 5ustar0000000000000000bz2-1.0.0.1/mem/Mem.hs0000644000000000000000000000127507346545000012372 0ustar0000000000000000module Main (main) where import Codec.Compression.BZip (compress, decompress) import qualified Data.ByteString.Lazy as BSL import System.FilePath (()) import System.IO.Temp (withSystemTempDirectory) main :: IO () main = compressDump *> decompressDump decompressDump :: IO () decompressDump = withSystemTempDirectory "bz2" $ \fp -> BSL.writeFile (fp "valgrind-3.15.0.tar") =<< (decompress <$> BSL.readFile "valgrind-3.15.0.tar.bz2") compressDump :: IO () compressDump = withSystemTempDirectory "bz2" $ \fp -> BSL.writeFile (fp "valgrind-3.15.0.tar.bz2") =<< (compress <$> BSL.readFile "valgrind-3.15.0.tar") bz2-1.0.0.1/src/Codec/Compression/0000755000000000000000000000000007346545000014642 5ustar0000000000000000bz2-1.0.0.1/src/Codec/Compression/BZip.hs0000644000000000000000000000116407346545000016044 0ustar0000000000000000-- | High-level functions throw 'BZError' on error. -- -- @since 0.1.1.0 module Codec.Compression.BZip ( -- * High-level functions. compress , compressWith , decompress -- * Errors , BZError (..) -- * Miscellany , bZ2BzlibVersion ) where import Codec.Compression.BZip.Foreign.Common import Codec.Compression.BZip.Pack import Codec.Compression.BZip.Unpack bz2-1.0.0.1/src/Codec/Compression/BZip/0000755000000000000000000000000007346545000015506 5ustar0000000000000000bz2-1.0.0.1/src/Codec/Compression/BZip/Common.chs0000644000000000000000000000074507346545000017443 0ustar0000000000000000module Codec.Compression.BZip.Common ( bzStreamInit ) where import Codec.Compression.BZip.Foreign.Common (BzStream) import Control.Applicative import Foreign.Ptr (nullFunPtr, nullPtr, Ptr) import Foreign.Marshal (mallocBytes) #include bzStreamInit :: IO (Ptr BzStream) bzStreamInit = do p <- mallocBytes {# sizeof bz_stream #} {# set bz_stream.bzalloc #} p nullFunPtr {# set bz_stream.bzfree #} p nullFunPtr {# set bz_stream.opaque #} p nullPtr pure p bz2-1.0.0.1/src/Codec/Compression/BZip/Foreign/0000755000000000000000000000000007346545000017077 5ustar0000000000000000bz2-1.0.0.1/src/Codec/Compression/BZip/Foreign/Common.chs0000644000000000000000000000415707346545000021035 0ustar0000000000000000{-# LANGUAGE DeriveDataTypeable #-} module Codec.Compression.BZip.Foreign.Common ( -- * Types BZAction (..) , BZError (..) , BzStream -- * Helper , bzWrap -- * Contributed functions , bZ2BzlibVersion ) where import Control.Applicative import Control.Exception (Exception, throw) import Data.Typeable (Typeable) import Foreign.C.Types (CInt) #include {# enum define BZAction { BZ_RUN as BzRun , BZ_FLUSH as BzFlush , BZ_FINISH as BzFinish } #} {# enum define BZError { BZ_OK as BzOk , BZ_RUN_OK as BzRunOk , BZ_FLUSH_OK as BzFlushOk , BZ_FINISH_OK as BzFinishOk , BZ_STREAM_END as BzStreamEnd , BZ_SEQUENCE_ERROR as BzSequenceError , BZ_PARAM_ERROR as BzParamError , BZ_MEM_ERROR as BzMemError , BZ_DATA_ERROR as BzDataError , BZ_DATA_ERROR_MAGIC as BzDataErrorMagic , BZ_IO_ERROR as BzIoError , BZ_UNEXPECTED_EOF as BzUnexpectedEof , BZ_OUTBUFF_FULL as BzOutbuffFull , BZ_CONFIG_ERROR as BzConfigError } deriving (Eq, Show, Typeable) #} instance Exception BZError where -- | Abstract type data BzStream -- Contributed functions {# fun pure BZ2_bzlibVersion as ^ { } -> `String' #} bzWrap :: CInt -> IO BZError bzWrap err = let err' = toEnum (fromIntegral err) in case err' of BzOk -> pure err' BzRunOk -> pure err' BzFlushOk -> pure err' BzFinishOk -> pure err' BzStreamEnd -> pure err' x -> throw x bz2-1.0.0.1/src/Codec/Compression/BZip/Foreign/Compress.chs0000644000000000000000000000125307346545000021372 0ustar0000000000000000module Codec.Compression.BZip.Foreign.Compress ( bZ2BzCompressInit , bZ2BzCompress , bZ2BzCompressEnd , BzStreamPtr ) where {# import Codec.Compression.BZip.Foreign.Common #} import Foreign.C.Types (CInt) #include {#pointer *bz_stream as BzStreamPtr foreign finalizer BZ2_bzCompressEnd as ^ -> BzStream #} {# fun BZ2_bzCompressInit as ^ { `BzStreamPtr', `CInt', `CInt', `CInt' } -> `()' bzWrap*- #} {# fun BZ2_bzCompress as ^ { `BzStreamPtr', `BZAction' } -> `BZError' bzWrap* #} bz2-1.0.0.1/src/Codec/Compression/BZip/Foreign/Decompress.chs0000644000000000000000000000125507346545000021705 0ustar0000000000000000module Codec.Compression.BZip.Foreign.Decompress ( bZ2BzDecompressInit , bZ2BzDecompress , bZ2BzDecompressEnd , BzStreamPtr ) where {# import Codec.Compression.BZip.Foreign.Common #} import Foreign.C.Types (CInt) #include {#pointer *bz_stream as BzStreamPtr foreign finalizer BZ2_bzDecompressEnd as ^ -> BzStream #} {# fun BZ2_bzDecompressInit as ^ { `BzStreamPtr', `CInt', `Bool' } -> `()' bzWrap*- #} {# fun BZ2_bzDecompress as ^ { `BzStreamPtr' } -> `BZError' bzWrap* #} bz2-1.0.0.1/src/Codec/Compression/BZip/Pack.chs0000644000000000000000000001122207346545000017061 0ustar0000000000000000{-# LANGUAGE TupleSections #-} module Codec.Compression.BZip.Pack ( compress , compressWith ) where import Codec.Compression.BZip.Foreign.Common import Codec.Compression.BZip.Foreign.Compress import Codec.Compression.BZip.Common import Control.Applicative import Control.Monad.ST.Lazy as LazyST import Control.Monad.ST.Lazy.Unsafe as LazyST import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Unsafe as BS import Foreign.C.Types (CInt) import Foreign.ForeignPtr (castForeignPtr, ForeignPtr, newForeignPtr, mallocForeignPtrBytes, withForeignPtr) import Foreign.Ptr (Ptr, castPtr, nullPtr) #include -- | @since 0.1.1.0 compress :: BSL.ByteString -> BSL.ByteString compress = compressWith 9 30 type Step = Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> (BZAction -> IO BZError) -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) -- | See [bzlib manual](https://www.sourceware.org/bzip2/manual/manual.html#bzcompress-init) -- for information on compression parameters. -- -- @since 0.1.1.0 compressWith :: CInt -- ^ Block size (@1-9@) -> CInt -- ^ Work factor (@0-250@) -> BSL.ByteString -> BSL.ByteString compressWith blkSize wf bsl = let bss = BSL.toChunks bsl in BSL.fromChunks $ LazyST.runST $ do (p, bufOut) <- LazyST.unsafeIOToST $ do ptr <- bzStreamInit p <- castForeignPtr <$> newForeignPtr bZ2BzCompressEnd (castPtr ptr) bzCompressInit blkSize wf p bufOut <- mallocForeignPtrBytes bufSz pure (p, bufOut) bzCompressChunks p bss bufOut bzCompressChunks :: ForeignPtr BzStream -> [BS.ByteString] -> ForeignPtr a -> LazyST.ST s [BS.ByteString] bzCompressChunks ptr' bs bufO = do fillBuf ptr' Nothing bs pushBytes bufO where -- corresponds to inner loop in zlib example fillBuf :: ForeignPtr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> Step -> ForeignPtr a -> LazyST.ST s [BS.ByteString] fillBuf pForeign passFwd bs' step bufOutForeign = do (ret, szOut, newBSAp, bs'', keepAlive) <- LazyST.unsafeIOToST $ do withForeignPtr pForeign $ \p -> withForeignPtr bufOutForeign $ \bufOut -> do let act f = do {# set bz_stream.avail_out #} p bufSz {# set bz_stream.next_out #} p (castPtr bufOut) bZ2BzCompress ptr' f (ret, keepAlive, bs'') <- step p passFwd bs' act szOut <- fromIntegral <$> {# get bz_stream->avail_out #} p let bytesAvail = bufSz - szOut newBSAp <- if bytesAvail /= 0 then (:) <$> BS.packCStringLen (castPtr bufOut, bytesAvail) else pure id pure (ret, szOut, newBSAp, bs'', keepAlive) let step' = if szOut == 0 then keepBytesAlive else pushBytes if ret == BzStreamEnd then pure (newBSAp []) else newBSAp <$> fillBuf pForeign keepAlive bs'' step' bufOutForeign keepBytesAlive :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> (BZAction -> IO BZError) -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) keepBytesAlive _ Nothing [] act = (, Nothing, []) <$> act BzFinish keepBytesAlive _ Nothing bs' act = (, Nothing, bs') <$> act BzRun keepBytesAlive _ passFwd@(Just b) [] act = do BS.unsafeUseAsCStringLen b $ \_ -> do (, passFwd, []) <$> act BzFinish keepBytesAlive _ passFwd@(Just b) bs' act = do BS.unsafeUseAsCStringLen b $ \_ -> do (, passFwd, bs') <$> act BzRun pushBytes :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> (BZAction -> IO BZError) -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) pushBytes _ _ [] act = (, Nothing, []) <$> act BzFinish pushBytes p _ (b:bs') act = BS.unsafeUseAsCStringLen b $ \(buf, sz) -> do {# set bz_stream.avail_in #} p (fromIntegral sz) {# set bz_stream.next_in #} p buf (, Just b, bs') <$> act BzRun bufSz :: Integral a => a bufSz = 32 * 1024 bzCompressInit :: CInt -> CInt -> ForeignPtr BzStream -> IO () bzCompressInit blkSize wf ptr' = do withForeignPtr ptr' $ \p -> do {# set bz_stream.next_in #} p nullPtr {# set bz_stream.avail_in #} p 0 bZ2BzCompressInit ptr' blkSize 0 wf bz2-1.0.0.1/src/Codec/Compression/BZip/Unpack.chs0000644000000000000000000000772307346545000017437 0ustar0000000000000000{-# LANGUAGE TupleSections #-} module Codec.Compression.BZip.Unpack ( decompress ) where import Codec.Compression.BZip.Foreign.Common import Codec.Compression.BZip.Foreign.Decompress import Codec.Compression.BZip.Common import Control.Applicative import Control.Monad.ST.Lazy as LazyST import Control.Monad.ST.Lazy.Unsafe as LazyST import qualified Data.ByteString as BS import qualified Data.ByteString.Unsafe as BS import qualified Data.ByteString.Lazy as BSL import Foreign.ForeignPtr (newForeignPtr, castForeignPtr, ForeignPtr, mallocForeignPtrBytes, withForeignPtr) import Foreign.Ptr (Ptr, castPtr, nullPtr) #include -- | Don't use this on pathological input; it may not be secure -- -- @since 0.1.1.0 decompress :: BSL.ByteString -> BSL.ByteString decompress bsl = let bss = BSL.toChunks bsl in BSL.fromChunks $ LazyST.runST $ do (p, bufOut) <- LazyST.unsafeIOToST $ do ptr <- bzStreamInit p <- castForeignPtr <$> newForeignPtr bZ2BzDecompressEnd (castPtr ptr) bzDecompressInit p bufOut <- mallocForeignPtrBytes bufSz pure (p, bufOut) bzDecompressChunks p bss bufOut type Step = Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) bzDecompressChunks :: ForeignPtr BzStream -> [BS.ByteString] -> ForeignPtr a -> LazyST.ST s [BS.ByteString] bzDecompressChunks ptr' bs bufO = fillBuf ptr' Nothing bs pushBytes bufO where fillBuf :: ForeignPtr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> Step -> ForeignPtr a -> LazyST.ST s [BS.ByteString] fillBuf pForeign passFwd bs' step bufOutForeign = do (ret, szOut, newBSAp, bs'', keepAlive) <- LazyST.unsafeIOToST $ do withForeignPtr pForeign $ \p -> withForeignPtr bufOutForeign $ \bufOut -> do let act = do {# set bz_stream.avail_out #} p bufSz {# set bz_stream.next_out #} p (castPtr bufOut) bZ2BzDecompress ptr' (ret, keepAlive, bs'') <- step p passFwd bs' act szOut <- fromIntegral <$> {# get bz_stream->avail_out #} p let bytesAvail = bufSz - szOut newBSAp <- if bytesAvail /= 0 then (:) <$> BS.packCStringLen (castPtr bufOut, bytesAvail) else pure id pure (ret, szOut, newBSAp, bs'', keepAlive) let step' = if szOut == 0 then keepBytesAlive else pushBytes if ret == BzStreamEnd then pure (newBSAp []) else newBSAp <$> fillBuf pForeign keepAlive bs'' step' bufOutForeign keepBytesAlive :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) keepBytesAlive _ Nothing bs' act = (, Nothing, bs') <$> act keepBytesAlive _ passFwd@(Just b) bs' act = do BS.unsafeUseAsCStringLen b $ \_ -> do (, passFwd, bs') <$> act pushBytes :: Ptr BzStream -> Maybe BS.ByteString -> [BS.ByteString] -> IO BZError -> IO (BZError, Maybe BS.ByteString, [BS.ByteString]) pushBytes _ _ [] act = (, Nothing, []) <$> act pushBytes p _ (b:bs') act = BS.unsafeUseAsCStringLen b $ \(buf, sz) -> do {# set bz_stream.avail_in #} p (fromIntegral sz) {# set bz_stream.next_in #} p buf (, Just b, bs') <$> act bufSz :: Integral a => a bufSz = 32 * 1024 bzDecompressInit :: ForeignPtr BzStream -> IO () bzDecompressInit ptr' = do withForeignPtr ptr' $ \p -> do {# set bz_stream.next_in #} p nullPtr {# set bz_stream.avail_in #} p 0 bZ2BzDecompressInit ptr' 0 False bz2-1.0.0.1/test/0000755000000000000000000000000007346545000011514 5ustar0000000000000000bz2-1.0.0.1/test/Spec.hs0000644000000000000000000000362507346545000012750 0ustar0000000000000000module Main (main) where import Codec.Compression.BZip import Control.DeepSeq (deepseq) import qualified Data.ByteString.Lazy as BSL import System.Directory (doesFileExist) import System.FilePath ((-<.>)) import Test.Tasty import Test.Tasty.Golden import Test.Tasty.HUnit testDecompress :: FilePath -> TestTree testDecompress fp = goldenVsString ("Decompress " ++ fp) (fp -<.> ".ref") (decompress <$> BSL.readFile fp) testCompress :: FilePath -> TestTree testCompress fp = testCase ("Roundtrip " ++ fp) $ do contents <- BSL.readFile fp let actual = decompress (compress contents) actual @?= contents testValgrind :: TestTree testValgrind = testCase "Unpack valgrind" $ do contents <- BSL.readFile "valgrind-3.15.0.tar.bz2" let actual = decompress contents assertBool "Unpacks w/o error" (actual `deepseq` True) testValgrindPack :: TestTree testValgrindPack = testCase "Pack valgrind" $ do contents <- BSL.readFile "valgrind-3.15.0.tar" let actual = compress contents assertBool "Packs w/o error" (actual `deepseq` True) main :: IO () main = do valgrind <- (&&) <$> doesFileExist "valgrind-3.15.0.tar.bz2" <*> doesFileExist "valgrind-3.15.0.tar" let go = if valgrind then (testValgrind:) . (testValgrindPack:) else id defaultMain $ testGroup "bz2" (go [testDecompression, testCompression]) where testDecompression = testGroup "Decompress" [ testDecompress "test/data/sample1.bz2" , testDecompress "test/data/sample2.bz2" , testDecompress "test/data/sample3.bz2" ] testCompression = testGroup "Compress" [ testCompress "test/data/sample1.ref" , testCompress "test/data/sample2.ref" , testCompress "test/data/sample3.ref" ] bz2-1.0.0.1/test/data/0000755000000000000000000000000007346545000012425 5ustar0000000000000000bz2-1.0.0.1/test/data/sample1.bz20000644000000000000000000007713407346545000014422 0ustar0000000000000000BZh11AY&SYÌñµ¥¾¦ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà”ßx> Y;aÛ»bµÌ6¬ ½ô}m˜Áè:ëÙÃ轘€n½Ý»îÖnMîç¶ ÎJ°ãÛ6ö³Ì¶ë‡£z±-˜)³›]{wom¹s§[r»¸u°ˆ„Mt¯co¬}µly;³èhÏ-ÓI»ÇµoxõN¦ã¯n^ó¶ÞÝïeì7žíq½è£^|÷i§lØÂ}ð§{¾¾ìoµõ¾ûãѼ¬ëED†Iñ\›ÝkÐô”… ¼öÞŸ^øÛçÖÝï;ÛÝ˯yÝM¼åW³ÕOvç«`‹ÑòûÛÃë|ù +âçw[àç”l2[¾ù¾õö»lõ ( UmŒÇÖuЂƒ ÛW¶ÞÀ}P¯u¸Å†´ж^÷$ÜÕAìÚÆ„ØÀ/cSïw0FÙ€•µM] M"4Ó@h44ÐidL4ÑÐ “bi²S=ð§äÄÊy¡OM4Sðü†‘鈙‰¦OE6š1O"<‰êm4i¢f…§   …OzIâzŒF mS5=OÔOSj ÄÐ@êzh  F@LD€‰¦¦mSMIèmCÒdÒ43A¤z™š¦šzš=&ŸªbDÓÔôŒ€Ñ§¤À “ˆhddÄa ˜˜ÓM144£M14šHˆ@ALJx“ôÈh¦õO(ÓOSÓM#É覌Cõ#Ôòê6¡¦šdhõh?Tiz&šz€ Ô =MP4õ¨z†šiˆô𔉡 é0š©þš§µ0šhÒOÐ4ÔÙ4O"jz4ôSÔ˜ 4̦ž“Ôõ6Šdü“ÔÉ6§„‡©¶‘é=)êm Ê›Ò5"zOF=CM4Fž¦ÒOSÓÓSM ê4{E3LÔA"!!<“MDò§é¤ôjzjž šSÒª›=©4ñ'”4z2™”õÐÔmGêM“ÔyCÐÓF!¨z™”Ó@Ó&žPdýMCL†ƒÔÉê6¡§|fBD«^ͬ1Ë6}uh׳kkb?˜ò21%vˆ†hÑÔHfÀMp‘4$à€ÛŒ÷?T~Y®=2êÒåF¸4û»rérQRšLpC01„ÈK *C3E­iJ‹(‹¦ŠF0R,ih±ŠŠ¢¬DUa™† Ä-)ôˆHaAVnÊÁE»a–¢å¢Ä·.\¹J­µ- !–¬X¤b«U¢©Z\j9hÅÊÚŽ4TX,Tq©˜\Q@b1­jåª*®- ¢Š˜ÕUÚÁOAØ‘Q¦ ªQ©wpRÑ*\Eˆ±Xˆˆ°U"fbÅœ}Ùïˆ+ ,U‹ û¼Ì@®¹jþt‹ÂgÊ(™^A1¢Ž„êO¸V|zR£tVÒœáž5'b\:chŠ\É‹nG6P3PC€@ÔEm0ª) 2#"hb~U]Œ‘ *[")¾R*˜‰rlµX¸Ê-J[$Ä’Œ   ¿adHIìÑH«Pc!$ HßANÁìV‹ÉA{êÖ¿ì‚ ;÷?þúÍÃPÔ’ ˆ2$©4CGÀ >‰1¹áÉ„]*ôM‘,cI(g· ‡Ë^’û/½°OÖŸmçâÊ™Eƒéoˆ5«'ö ©Â¥¶Ÿ“—ˆ‡îy kC*±:þS?i ïØ2ºµh©s˜ÁT\j,ŸnÑY–ÿ0´\e´DRV-´k[J§ÖRª¢¢®R¶”±m‘Q‚—²¹I!h•–(ª*%*…Q•©j4"ÅX[hˆ…¥EjJTlŒTD•ª è4TX§ ’&•GMRÙU¨b”TFÛ ÕËaET"*1-²Ø#bµY*-b¶¢(+GõÉQƒjÊZR±k hÒŠD´X¥J¨(QƒRÅ©PX”w†&%´*V´DQYKFÐkEd¬FÛ%` ”-¢%‹£EàÊeZ ÒÖ†„ÌýµÌ¶®í2Ê%­­AŒm¥,VÚ”R¥¶ªÖ)X ”„iªÛ*Ù…©ŠááVŒ²ÙFRÖµk}9 DjTQj¥¶Uµd³ óS5d½D³în± Ú‹‚`~äS rqoÞ¤ª•ØbIˆSÝM@N·³ð¶sv\8@3Ñ8X²,ˆ#$¤…B(’¢Á¶¡aE€ ¤UPŠ ¤‚’¡XJÀY"Ű*¤¬„¤ Ê‹%¬²°PŠE’Qª‘`ˆŒ”,–ŒbÁ„ªŠ°FD`'àâùXÊÑ!8‡O¡é¸¯7·ôN'6ZÆ ö;^ÀÖMn…¾”4 ÙyŸs ³ 4Ü~ºÅ Ëh²GA9£‹ù Üä¯}4 Àa36e/õ;oÎUç!ˬë»sŽI¦$X"wÅ–ß™!$‰ŽÍž (eÄF4Ìèé“ %ÕfÈ…°¸×Êq1ö!Ìu¼:ò¡$*\tpñ»îp¤P‰paw¶þi/•’ú©Ê)V*Ìo;Îs³š¤Á¾ÞÇuš¼sv÷J4 _;t,±¡Ò£¡áºƒA¬NGƒ’ ŸŠ‚"2" ÉH,‰sï |q'´ä÷ûÃ7ó Tÿ˺¿èwøç€ÝK¹s‹÷q¸O×ÎÉÎ}dÐh ìÜúJv•<”i g1ÐýÔÒ[ôµQô¢q_ÛaØ·û"Û¶ÒŸ–_ëŸÃuûi]¿WÛõ?U¿BÜ8Ï/°Ó_Ûc³~9eS¬‚; îúzœþ'›ay‹Ž<•aF«ïÂû»{¥QùÛ'¼]ñÑøWñÃÉ´_>uܹŽ_I±d>¾ñ}¬›Y)%ª‘Õ7EP•>ãù4‡Êên°^9qλ°Ì|RÆ[%¡s!&â·:²I¢LáÕØa©Pñïâ×ïZìI&ç_.‹ÉaÁ¾cz•ùÄ.šÑ>É®fflG`CÕ¯5!ZÎÿFgû_o; åÜ×’‡?GËHñšre³T¥£? sÏ­ÕÏR4èÕâØ™ñÖ5ÔËûφ¿ E,µ–3ž¨<tO—îGÔmbøL }è°ù‰HË}ýjô³ÚNmGßÉ¸Ãæ»,-S™#ìÓì±ïýÏ(½¾?-+ìRåU SÂ…[(D²—Œ@ø;z×ä®ðÒP.K¾|ô¢íè¼Ë”ôá à¾D»pm g_C øP1{õ˜ÿ*gÖ¼ƒyÏûžeÕ“˜Ÿ²èi´Ý=MúÀ펾xú¹÷gÎ8+"•~rª{­Ö¯®¦`.''/ºŠRƒìG“G³<'‡î[çÙGîæœ9dÒ÷,B‘ rÞ®¯Ajdí)ô¯,üŽ6ñÞt^>œ:äxœÐšX̹j8Õ *M_"Õ9ô²Ó±9q?m¤Í­‘íýï¿V÷w“¶Þº>ÒµYp‡¯­$ÊÔkT‚Îêµò´å›ÂÒcb %«)¼¡hæQwínü&*¦ù¥ºG)!®§RAªû€›˜CáØ`áûUFümŽï¿láºÂ*1Œá`¼õ7©O³Ö.-)'cçɘï°àK=Ááœ~a3ˆt“¯€$ :LØÿ4Ë gôø¾ÙêO¼ç6È31Šk/:\Ýš ÞsŠÙèOy9Àˆ¤€‚²0èBd†a!€æÍN·ÐäY¨U¯¦ÔéI×HĘ/6eQÖ7#˜ÍfÓåO.mÔÛµÔ³Op¼Ç,›o–Ý•‹W Æ`iÙ]6^÷qˆØ†ä`“\¯Vš…rt”b2B”“—â„+Ë}ÿ BáP ÿ(°’{€¬ç°0S×XYë%vä_` 6Xêjt}U\Λ¦¦¨«Y3x8ðÆuRsñPK%ËÙ¤aM«‘ãá¸àRžá_›Œl~« zS¿vÓOåëþ®má¶ü ¿ë1ñ*I$÷ªYÈ壚žÎƒ'õO1ð7éùN›Ñ¬^X7w¥PÆŒÈÆ.\¡ïŸ-‰ÂÉ›VKÙ,qÅ"Åïòäý/éÿS¡ªÔß ±ZFƒÁY½ŸþÑOl-€Ž6à‡ÌOÇ~n-›ÑzmÀ| ¹|кnÂÖp>ƒ3hÙCt¸+ë|Ã!¹³[ñ:îmÈA¢Ñã631F_˜Rƒ¹––P1ʹ½f\œZ…mw•ÐÖØ)“6¯MÅßotØ’à>‡uŸãéRû+",Š’B2$ˆÈƒ`Úkè17 %r³ét÷üŽÇ˜ìÒ”¥4yFñ³ÜþYâ |ÿ콿Ùv"$`rìâ#øÔ‚²çñž}éQ ϦlÝtðzôqޱéD4\þ7Þ?·cÇTBo8o¯ÓiÇ'G÷¹ï8ó îZê­ùwõò0n çÎ%’I!Cþ.x_δ¨ùÝäýY“øþß•>ÝS`øÜ½ga1¤RqD ”¿êo£¹™ÝwZrTÏzŒ"0z§eš,~S¯ «0rWCøÅÏÁÚ}èç ¢0:c‰ÙuÇêè:ù#qû®Î¾ŒÜÊK <æëÃÌDnÓŽëõL˜Ý¨*ò_NÆkàtrÍ‚‡õ*ÿR“>‡nôsxØøk^nO≘ÞÎÉJ„¨…`°¬ ŸùCúôrpÜ#ív\õÎ#÷ÌQw»B Íß¾¨’áÔÑž·W—˜´P¹Ž‡'e™D›ŒÛ<õÜOaÞîgïÞÔG:DÄ©ˆxwWCÉN™ Ü䛡C§öEù ¸Çì°Cgñ(ú4ÿô“Es1%?ˆB?ÕÛÚüOšWS{ˑӕµgË]Xä2“cÿ¶/ðð¶£Jé>j;´4òŽÒ¬®”›akBE®¨£+)º²¾}ÝWƒþù--Jeõ½ðìÞŸ[õ7Ê)Ô•däY×UìuîwG.ç_Úr5n î9Bsàÿ›íƒí禭`k%@-´kb …ŒX()ÁVƒЬd£"°H±Y …k )`T‚ÈTBÛcY ‚‚…diQ€0k$•$* aU‘´,(ÚT‚”EŠ) ‚ÈQ%lc*V¥bA%H°YEˆªª£H" DED%Ab‹"`e¨§µ/i˜'w<,©¬;ô½…Þ­D×ÌÁ´ÀšaQ˜³'F0èb¦w"ÜöËq䎔.v!••ôue?–=O-‹`½ÄV‹ï~Ì0S4X¥4©@qrU#  ¿ãè3ñƒõxÒl­Þ ¼u0ú‘—Ýãû,1†Ñq?]ÿ9ÁÔ+{‹Îë¿¿Ã’löEãISÿx[=½¶ÁÈ©[Ðr¿Œçˆæf×Ýyµ Io å¸z¦»#Æú/™¾8)ËÈæ¡á]ó­‘ “¥_|_ìšæ*šn663s7>ž×9Ƴœæ[¹±cô칫­@-ëíÅB¹oØ&9CÌ)°ÚdpƒmñÉ}®%?Ü Ó©x¿äÅÆ±$žÚ¤ïÇ&Üòn½­ŒÍ|‹S}"ôŽFù¨¦xêOÖ±Œª’ÕLô?Ÿ““ÃT¾^†.ŠJ’©·È•úh‰ÛïÀµ—Bƒ¤3ßÜAŽÿ8ØEË™'N‚*ú“g!v=ä/Ô"aB…DÝ]0`Ðû̺ê  _©â‘ü–nÆÑ•Œ8mËìÒþÛì½íë»ÕÜsÆr•MúæðühG2ºÙü4Kw´gC‰#lz-éföX•¿‚n1ÌÖÇÎáRëäuÎåìšïó|z·–ùËÞÔq‹ÐÜy6¯øGÏV ÍOTm€ ¹–ÁÙßhý?—r]̶2?/ƒóäÌk^Çs›ÝsòáûnfÁ]7uÊÒúÑlâG›så^JïPì¬èžþòÛ$ {å`ßµ/9覼îrXnþ;Ö垪KRËŒäµÊÈÝ?[ë,JS@CÖZ+7|.%”Ô‘À¾cƒn²¨ŒÂo®’a/Y˜5ùŒ  ¬§‚ Ù^8¬\ m½MÂŽ,güŠÏŒïàtvA ‹›©^ÞkÖº©’ó«1¶„ Kÿˆ¨róU‰ã£Q²’’¦Î•6»›¬í}ÈëÔ¦&$£÷ DZ32Rð²÷ʵ›$2SG‹àµ°ð›5“‹'Õ³VJ§øïÓ\š;G©–Äþ@€EÛ¨„ *"2 "( B+77-˜7WYYbßÁÎCÛ^¢ßŒ"„Ccý”7¤í^[½Èý¾ˆ=æC]o‡=Æxºß7óÃÃÿBýaëý•ÂRÂbmvÄ«½ö¨#†÷;εàÆ÷vfcÂÁ³ÍbñÁ/Ãô‰nÄpåwôš¦“}þÕ›Nš¹óßä1ù ÙJƒW¹Ñ0Ö0ÈÀµQjô² S–JeÍ BILØSÞšüœïÄå.ÉQ5¿ç Þ½_aåÙXž)?–þäjÖ ORÏé£ôÔ>áÒDúú],’DŽû×íÚŽ®NwÂBIq»EÝG²ù>ªïŸàÒz%$ðb¡:òÿ$·Ï«K¤Ai°{,“øÞöøT¦USCЩ´–œÓ¾AZöLÀH\Õéüš&<óêœy Õ&à4´»8që®7­ôf`jçE÷N{Ò«Sýazs˜§pÕ>ëäù¥õóy|‚eKD(pÏÎ÷×b»Uœ(¾â± À?dùÌ mÚp‹8Qþï?§Úû‡¡;£hr™fЬŠjû>Ò›ùÄ/iMšî/±(äŒ`W÷¤Uǃ‡:W¯žá´E×¥]½Kêé ûÑò±óÒq® eÊjeZ2 Ç›áM9hUE ©CE 3QÑQ´çþŽKñµ¡m÷^„NYº^)ÍâÁ:˜À¶Ð ‹ùIE”’GQ…’J(ÈT;¦F0¦ü)ÑŽóÇeòcÁ‡ šûü‚¨a~Ž`ÈÑðóí_ͯô²>‡;Bt¢ì1Ì|yñ×¥TЇ ¼"‰Ý«ßºl[ ¿ èqÑQŸQhœÓ¯¦q§nµq#æµ:r‹RÝ3ܲVƒp!‰Y›û|‹:G ‹¢‚¬ŠçžzÓi×ãÓ׎D+þ™§ZÚè–°xùŠÂ†ª”R‡Ç0ZkÃÀXå·Ûg±{$¾C‡³H€Di0G¸‰C÷ìs[–M*ñ çýõ/@jeÎÀQ‹¤ÁþP€ôpb&=ZhW”øz“ÈÑé4ø9²X¼ÝÓ !ŒÇl\J»í>Ï”«­BcàäÂÚÉ^ó-…m…6c  ›#­N»º›-2‚8a:kV×{ÁxáW]òOS8êþ“=f—Ñ‚Àä¤*gÞ|X3CÀÏ;±DIFRrÃ_&|&ZŒ9xŸÏþõ‚YÌBŒÓ7'Ôâí]Og>;KٲϘËÞ,8Ú|ت~½—–æ5Òз—­¦LÙSØÌ·æ²²t¨ôOaIgwa1&©^ªýþ¹î¨ƒäôö„ŒsÁCýŸÄ¤èÏâÙ?ZüôÒAdê*‡Kôg†§NîZO5—{#ÆÌ×HÞQÌdb@³ÙÔ¿±ðl£óPÆö®!EåÖŸ»›Ò_VW¦xÎvWÒµW¯î¡y×Ó¸ûÌb•½iv3¦ið'oÎeœÍšŽ)Eö‚­#8FƆæXÊ&•2'ó¾C’µ(¦’§ïÒ 5yF½¢éoÈèUÅÓ¢td&IXr„~¤F꘦I¢ˆò¿ýÅ6hù¼¢77ù’l)v')Šóĵ(æ%Aõ<\_1qÆÎÉkõx´;Y•¼+n¾°b´¼êåç,ñWÝ·J±rcOI§w;¨¹ ÜV˜ÀXËgàr¶vþïi»V¿«ÚÎYéÕyåEĦznn¤ ’ÇFzZ÷Lâæ‘1ìïÃ+*Ý ú&•‚V>-ä"’šºR¼L¡ïcþEv).%P]Tï¿‹¿ô,9#Ƨ˼Øt™H÷PBÔTC"„Øõ¾¢Ô0HÐ#Óu]ùÍí^kFÞæwÑ$ÉCΞËZ})ÞƒDPš’iÁÉ2 4BŸb7É N›¸°­ÅÅ‘’î¶Ʋ€€nÇßt#bCÚÖG@lŒBhUB Ež`¹Vnꊶ®ÇcŒF›¸7I‚ü–š"ç9Ö‡«V#¹õ¼鵈É$yG]g¢pÝdš|ÄZ­>¥Ñ+¦fP˜Má Bg&æ¤)¥j±¼¢,h»<`¾Š¦i†ÃJQ)dIKõV"Ï|‡ÙìºGÄÐu…#²ä\š[%9Ý*ák"–¿Gø®‰S¬ô†lA1äof‡€üòå"ͼ$ìâí-ÅFƒæf¸`®C»A:=åðÓbL8ë¿DˆèºÝd;tëÔHKYâQ…ï»[°åä<ù‡u““öÅv^úuÔ>f­Ü&ÒXÑ"siô¶4´›EcIy0Vü(ôÞ¾«@¸+VDj}8Z)ÿN^׎A‚9M#i0Ã.¦ËíBhâ»8/½0Çøe(·M³™–[‘øù÷J)ºïÊ{wÆOœkãõ«áŒ— ±°hci´‹‚("(¨Š0DTTQtìÄ8¦¼·‚Vè¬ù†Òvß6ó^¦À)¤Á|t^Ü6¦Ë,šþ“Àî^gkò(«Ë9rI#ŒAèЈÝûIWiQ« àδâQ¶ka ›HÿmŸU‘GÏqë§Ç†•½ÈFó‡ÛÒŠd Ô3Ñ !åì¼|íòÿ9öØô¾Çü®#¤{/ºÀ8¸±Ò¸ÿIQ7»µŒ½ÅÔ­]Hƒ —YºŠ#âŒDÁö&í@€¹N`Éúò£¬e‡ù¾ûé{h^*Äò!—­{ò©˜Ñ0Úc¡)iâb™cÁ2=#½âÈ7Êí© t1¹u1ì™ê­‚§;„è,m"лü´§Låwkª' –ÕÍJðqTš¢jp>¾ñçõ&ñû„ !»›ñôÕ/•œ¸/cOÛÙÕ:32á[±/\¹8ˆUiÁ’Nò¼…‘fÌ.”ãf¼UaõV<«£Ù4EßQ*õ{ò…ðF :B‚ŒÏ…‚»âr¢|/Þ;ý»a¯ÑX\ƒüN\þ¿(‡Èµ×õxb¦™Y(Á$PÖ¾D*G“þÐ~³3lú©rë×ë÷U½a<"Pª ® ™ùã»Zã¯Lû6º(Â]Y×ZÀé²å,Ke C…lâ;&Gr\*i›ÐT„ÔèæKp²‹ ilK‹ÂI’[Z‰ƒ'M÷½ù›O„×ZyÑ)بx|ÛY§ÕA ¨’8£(©¥KH¥d5Ϩ‚uÙ¢m:åï/Žqèt¶¢ªVˆ¢Ôêôv*Ž"Éíué¹ü~u{CÁÎàÅ~ÿ“»âoÖøøÒ=¯cE·Î¦-h”J*¦Iù•æäF„ák¹`Ú{3µ8£o½®ÿVîÙý˜Ëé/¸TêŒH˜ÂJf xøîÕA *ì^ï h¾×=ÿK!{7"/PwŒåè ÷³ ²H ®Aîh9òäa§ì*ñT-¾ûêšG¦¤â|ßY:á»W†žÝòrwö˜†TíhŠŸ®¤ç,æÔQú+:³6Yû‡È2Ï,!ž¯ e²³¥)J­SÁ6׎¥16ŸÓýÄêN‡ÏçÒ L­TË$iEÉnBh€@ü'ÛÔc´o}HþŸ;ÙbÞfás¥`˜ÄÄŸrµ¿&Èl६lË¥™/C~2Ⱦ|·0%¼='ètñ1elqFã¨ómO›÷1úîÏNHrÂçŽ"!3ºá˜Oñ¾V‡ÄþrÆØi%‰P#Ó&ãqè°bVÂÀ}Ab—Fº¦!‚†ž\Ëc8ÖblqLº£m¶á˜ËqÚD\5r+Z‡8úkÞWG."}-éœ)…4a‰Ã±ÂŽ<kmu£‹Á¬Õ¥\ã $\a¬,8IüÏì·½Nî)ÖÐÖÄ^ˆU|9ÝC2³ë_p¾¼.Áò¥'fÚV ›$H)IrB2nEôLÀÆ«‘S”¬ˆ¢¨é¯V}ê ÍÛYÝo9§îêâ3,ÕÖ:¸í\dËg&z̦”° êÈöxo™]+6Shœ‹N·*÷Ùnh»+bž Wßy‚G‘éøZ¯OÈàŽ†¾6}'_¥·+ô,%µÇ9¢Xž«6ýT#ªtšÓ Q¸Ue?»#ªb@Z"í&Ò>¾ém?q•ÜaSV Òk”<©7Kúª•­F ©{ÅÞ Ü‹–ÂEIÂntúï×ò®ôOA䦆Ï-–sE4´\ª“ØâB°û‚‘#äù}–õL!Ô µD¹¡€GÚËý/Tƒ‹â á‘0Q˜Á)õÿÒ ½=&wJf{ª C ”NUU|nzñORŽ ÖvÀéµ=ÖUÐ…i“K>²8Ã_ j •ZUÙÞ³(ße¶{©“¿Z ‚”¦ 2ÅÔÕÉÅšM¸€¢;_JfnÖ°^m(9î&™ˆ‹Òn1C†‘Ò©Kªe©êS瞬ޭÕe3/µÐ·Yø/0\_'/$Qß ˆ‰5çK:Ì ]ÌË:Û &®†ô|0‡&¶lU"k¶]6·z qÝsÐRÙÒ"Š $+¯œTѱæ 'rþŽŽ.­Ò˰é#ÐRPu+›l«Ï $ËÜn¿mÈoj–·µÄåg< å0™ï:L¢RóLs6f‰V2 9 Yp œÊ‚J8™îÙÀÏu/u˜@‰ãÝÌÓ€æ=G\ŽM.W!fˆÅ¸MË-PnT¢v·, q˜ñd ðZ2J±U§5 þ[Öh‚jSae § ;LɨÎÞØ0ËÄ2Õ¬ƒaÖaË~„¸q7Ëœ ¡ÕL×u3µ}…s–tγEíV^v-nw9¯L—yùa¹¹ê¸Švg»|˜q÷ÿ¯óé8¼NŸ|'g|žÂr×9Õ‘µÅŽöâ³Ïõœ\–. ¸ÏÂ>žƒE-€Xý¼–0²'êšF®Òä[‹ZòóQÔ½w½×ŸbâæßB~-ë;í–†ñäíb†þÐÄU¤üsŸ3Ñvîu·›mÍåW©¨IZÃ)VØ7²öMkÓ໤\/ÃêÙñ4SáCæU÷=eÀb›÷SŠÿ›}Ïá=l@ÁïÝá”/Ë 7GDúC×x$š÷Ù’@òñ>WÎûØÍmíÅé£)`‹âOÂuˆH•”òÍôÙÅËÍU"ûŤ<*¶5m`އå+'ÞZ/Hö(aKìPð¹²&ºC@Iô‘xÛaÔðéJ¤›B6ºC/.Íj (B¢ƒ½LQ•‚]È(–§ŽÐil +€ðÃc¡VV: $c ’”,Ô“êŒÍ—DÚ,!¶lq’{@DÒngT ¨4-eB@‘-¦8UšxÈ.L±(k¿–•×D01n(¼bÁÔð™"fw¨¨gcJá4•”í"qA×hÚ×µaš@ÉZH%)™“îr(­`¬¥|.ûáCª}¡ÝÒ ¾{yËä´kù€¨ÚD†Ýœ·è‹â*D2Á‹M©Q™˜åЄÊ:o5£#nN\¥ž(™§†yü{ú”íë¿›Î^H÷J£{½± £¬%’;SÚöÅ&XçÔËAKyë{"ºx—Ù½J‰æJ‰Åµž=BªÙK‡X‹ÂCÑMÑ*Á`Näm`•”–T‚•-‘}]–l²(pés1`±ì…Y ¥ .(+x0åpÓ•±,ˆV^ÆèìÈý£u)¾õ½®«afD@[-xºjïpÔ Q° Z¤¢Îµ !Bß -¡š€·Á(ÀƒB*ZŠE° $…- ÌrÅ6Æ­‰50íT‡*a‚f$ãIR©É¦ªÅC5ÅÙÞ!sR½lëö¯›Ùâ×”$—„̦ž,ÀíLØ4>,؆…jk<À€±Z­vßÓöþ¯ªÀ|ƒð½#Æwß§vç¿“Àï«ôßÃÜ„év€´´L½ÖWP›CSþâ4‘y¢tK·À—t¸S{ö½ аy=zLä鉣—N©à«¡y£JJ:VCȳÛx¸bB³ÒóV3rne‡QL$ˆ…¶ž¦ “(ŒÇÚ•÷« ‰²ˆaÁÀºPXÊT=…M’ (Ú]ùŠ(/s»Z–K”r¢Uã÷ˆ±èÓ_~(%abäˆ2)ÆŒ®ð1Vtì…“… p7‹*¤¬êEÛdboB¯gS‡È£}ãů™&ÈœAÚ…d܇•’Ld9±&EÒµ6 á2$m†/ÄsÖoE í¡CºL. ãIÐì z¶±Ð¨>4]]GBKPõ! åy†*år BvWkܼÅ!RÖ…ðѦ6`C@oD©6efÃ4ÄBì K¹¨ë'¨jø•EÊ\€Q ã ŠHpHh VvJ¯|×—¬±–`ðÿ‰é+kÖV¶E`¸xzz<ˆ*)¡"xQbzÅ1AåÓð'O‹À Ê|J¿#çkÔÐx+àˆz8 ‚‚.|ó3ÔÀK{YÝÈÅ‘KT’ïzÝLÞÂ}ç{#Yjï¶»PnB—«ÏWâ9;éY< ˜¯O6þÏ{µ/ kE6`Û5 ¥ÕX€ÅˆÃb¯=Qg9[­”’h¸$ƒ\Ah˜C _„b&C"þäB(Øè:¶ ÌIoCQ4dŒHHîV©H µÂê¯[|ˆ„M³*îŽÙ"˜8j¥òÕÒ6vɲo `ÕMý¥ g Í_C-sp•μ¹CùI˜¼ƒº˜@ŒÆ˜ÁEhXh,ù¢£ €XýH¨¾U- FK"ØÃ‚VÊ‚P‰T€  e(Õ©Ö\ê*Ö>Ò¤~áHßÇ_Jp9SA@½œ†J0$÷ÖX¯°qQÏ]v»®Zª[+.Âg!/,'+ÞÓÝñRiœYã»Sµ¤.FØâ!¬3ÆM»gÙ!Zî\]Í7ößn½zéíRÀUƒjmwµ^?‘~ƒ?…Ä]q/f´‘‘‚Þfb"­Í…ðxC°‘¤¶ö©mG…E»¦“#Dëéš+59,˜ =qUA@·ë õÿ™Æý¾ TóLÞ¦n¡d¯Î›œA ýÃõ¦°7—M†ÂC7é`"Æ ë1 1¢QÅù.1šá{Z9y`ñÖHHm`Æ]Í.9_éñâwI^ËÓÉ&†v–pr(Ú¡Žcîë¤þY2ÂsRŽ#êǃ^½ã©ó>?c€I0ªå¡ÂZ0–©£¢÷ ù¯ÚÑ[’t6tî’>þ«ÇŽO‘³’«XÀÁ F²6iJ!Ñ,˜$P¤]<¸¨÷“§· =BâI´†Ð:2Bć-V‰ÝŸž&x>ù«FŸ6XÙŸÖ>í—§xà‡ѺõÊÌš¡Cª< ¶¦þ©p뱑F°ðAš‹ûœ,2L¿ˆ +…Úƒœ Â4 ‚e/¼ña ˜ÛQ[Y˜æ;mæKîO±Ëg#GOoìžO¶èl=Ž:1oKÝX㸑bOyÁËö…¨Ó~ÑÂ÷¬‚ÜïŘØ`Ø¢'Oð¯ÞcóL;Ά%=VÀ$P)´6ެÓIíÏÓ?5b$±–¦ÙÙ0óüÏá×b„otzâcbïJÂ9š‡ä# qé20¥åñ€"I>B^ÒÂoDÃ5Š$p>ðý%F©W¢Í§q_ã³t€QZÃ0;½ƒ û¼°Š`Ç÷³aë9ëºIJSÀH#"ÁI01_]¢ÏÎ7@$ÀؾػF&Ç$H+†Ÿ#ÂŽM™Ìê2h°O‡áe÷½~3)1{³~Ù·‰i ÊuG|ÖUd*ýb¹·Ö”¼UA3^=ñš¡Î3vÄ2"ÎB! øÛs;Œ<-.¨rŒû'$AÌ­ÂtPæCÐÌÚÛ‹ª]ܨ¿.Êš¨Çr™l±Õާ¹§e¯˜ŸIé¬ÏÎÍ@°-¿ºá£R)+ì/Û<$©~M,˜X&)ÅG^^îÍÅÆZ×ߟ×e GäµËò`ùW@¸^ãDÁ㳆kø$cEÐÉ—É-f ××·Ó=ôÐX3P2µ”îÆW‰ZP†ó€Mê|l${]ÛÃ_=*XD^ Ô â”?"P80”@4IìG®ÿ@wÂÍ=§*x¯jÞ#¦¤òúLâ ”EÄ<ówŒÒmû£«M ›¢âkUX9ÆXj†¦Ø€ˆ1¹‘ ŒU8â˜ì¦÷†´Ò­6ZŽ-m»²œh±Twj )lPXªp£¦q…aáEDeoªI¦YÀ©XɺmÞço_WÔkEäîë©'RÑgÛϤC¤Bœý÷ZÈóþ\V{lÑð0Ñ.þåKxl[b†½5¤TC^^Ô„¦_*›´G—ã=ÚLȤNsƒ>‰w'mñsgº©ÍyFXÑP‚EÔT‚±‡‰ãI%yÍÓûz0ì`+ôt”Ÿ^d9|f˜Š{LUæá»›x„JeB²ApaY[Q X5v‹¬*Pd™`–ÆÇ0¶oRu{uzÓ!wý5GhÙ˜-å;ØØí“ÿ“6Hår7•#<= `:EȪ/¨¶J¢n°ÙuñBÇPP– F¯ÁÄÙÐÍ_S¿º¸þN'rû:][³]ã  Òè‘Þœ 5àdØn#D( ÿ²¸NXÔ’Èò¿ `ý¸‰ö~‚¤H%(»»(+1o•«x±"N;:Ò&îQéòÎÔ]Ûj¡ÂŠ‚¨oשøtúO]êä¼&cžæ°÷4}¢ö>I£\ôÅÀj%‰£hë9âB~Å4Ž„y8ë§mvÔÆ¿#N¾ÓEâð0͹΋Œ`ŽÃ­\¬ºcuã@ÙþŠÅÖ©™Ÿ#ò‚ª°dÛៃÓ_GK4?£dè©Ñæiÿ{iõ"šCcÓv< ÷RÞœ 4!E|*Õ¯yvaWhÈ¡V6©ŒÄÀÛìyQ·žÎ2Æò§ÏˆKÔ¸ì`á½QÙãz2û“2œÝè–¤B<ø$ûKøGì=M7KF'/Žªµ\‰%ˆ\;þû=Ïj‘ÖPÕAP˜Cµ(Tj±’Gd}‹SQ;yR‹È§¥—ê­˜46b²ñ¾Ç˜ÆQŽ‘-ÆwËädB³oO¨Üf#CCöÐå:ÖrÌ€d£VЪÞüÃP×P¹ûoY³åþ¬´SšPF%¥An\Ì¿+G¥w­Íú± Ãe[GPê˜eX®ŠdÏOCDª2’ï÷½?JYÓ³›¯/ª¨E&ªåãÄã‹bÌæÕÌრ"ÖxúS~y9k·õäfs0\áè-]꤫ÊG*´Fø“ƒE¡8€‘ŠYý—u$Ãueî²vœˆ,óçR*Ã}Ô PvqTe$ó¨óZ²Øœ :–¿k‹Y;ÊØ«yÍóäZؾõÑj «®èÚÂFn5S¶·ƒ¤Ð×V6#Sü<é3ÛëOºï3^ª½Ë ?NÐ*‘;é÷´•B.”жIìjdÐ’K#Cˆ±s“ª_‰g0¢’çíëµ`¤AÐõ|JÝ¡Š ¯Íñ.xž<á"+ó<u& ÆG+^I~_«ÊT5ýòÖ+Úµ æ²”á`.çx\1BÃ@Áº%è‚øœÍ,×@9Ah‚&ï0«/ލ‰?aµ`d 6ׄ…ˆ¢5(™kÒ\ȱrÑPbV “§ŒGb 9åg¬ ¦&«U)ùw®$½\ÝÑ¡°Ìá'M(;ƒIª—2£mx°20‚³I+ºHjâ­'>™<˜:eóÌñO}S u‰òž°“ÞBH v:÷TNô©Þ_XëÔ¥â+kBn’›)íÕIÝŸ…ÏÀ› &hå› ä9 ƒg_vir£V7T“)#¢º·Z÷™ä«ä÷¸ñKÖ—eöP4&e±Íq©QL­°Õ*м5:°ª¦jŒT˜ÑTPFéÂ8(#FT[j’ÛêäDÆÔ¬$ÁJÆtœ0DŸ–‹nà‘ Óp:‹Ëô.KYÌ·3õ½¨§ÍÌðƒx;íõ°8j‘5Ðzlño3ºMOf‹ ±µ-:‘ÒÒQŒROP{=ÁOUH±aÄî“Fa?ò,u {AÞHOµ¿ȰbŠDA`Œõz=öŽÜõÍhrŸ+JߪÀœÕ"ÛAAÄ®‹3¤‘‰±+ rBwªÀòÌòÔ%”QÁÜM&4´Ò({çøØPË4GWE”*–™•™iY¶ê«­8¡²´þ ãùcè-ÓtfË9«þÿ=†ÕebòWµJ¾:2¤4ì ¯vð¢ý?Í‹yÖ¡,1HÌ óZ ˆ€,TÑC~ÿظýÎwâ¢ÂËTÚl7{1#”!U[’IèXž©œÑ1x@P! ……Ï]ˆ¥Gkñ¼µÒÂïLãkÃ…ZÄÕçgjŒ4×2½‹:it¨Oä!ÀFHþ‘„J*1E.r$óµRr…{„ØM²A€üK½¥-ÝN5P vú^i%¾’+m¨¸¢†óü ª£C¬ª‚:i³!²ß ó¾ðѰ—§N¥t'làAtÖÝ8UAJ*¶(LÀ>&±çA+ЍsîuìOJu’Wð=ÿkd^¨ÊÞ©‚b±V[XˆªbÔü"æR²ØÐ°ÖLjý]Örwn¨¾ÆWM±a¡3,˜É¨“WžP×[¬Ãc9û«ÎBvB¶„ª& ôûbì(Sâ´Cô5‹ÖÔV.³táå—8”bëYs;bXfXd„Šæ:Ì¢ 1ØRµ8;ZλñßøþT‚õÖÕºz¯³¤ÑâöŠg“gÀ‚ƒÓ’kW€•F1¢JÀKC&v©á†òãä!„ÔWÜä‡K/tÆT—¿X°‹~Ìó@á’$PY".q2a[!A…Ž˜3ãs2ÚOŽÉ]h ’¥ C´§ˆ~º-”dez&wS,MøµÄùœ,ÛS Ñý dÒ 7„Ò0œ ø”YKB…¦Ù(È¢ ÇmUUŠ(è¶µE²‚‰¬¹A,-…w•™e hÕ“±-›+K ˆ6hš‘ÐZ0¬klÒªŠ|jJ…¥QHoNRÀc0dÞ©•™^éi×}k*b‡X™Îm¨XÂBÒ´0"Zž¢«Jr³!Ä‘8ò»êñ”´+%8–@‰/ðí$ôêMû `ìBÕV Ï¢èV 5F” ó”ËÞÕÜ-R½œÝ­º˜1\!A0ÍVÜ4TòÓ­jiãV]Y›Õ˜qjC²VIzÏ}ŸRôéÇLä˜MOZ«ÆÙA@Ûfýi%çIËmï¨! Æ0š†f1$hPÊÜ¤êæµ¼«›.;„¿@æ7eÅË–ŽvUÉ\ÝQq6×-ËŽ”Lp`\^‰ƒÅJ]ÁG$\ã »µöë\ÌÔMMXR90é¼Ní`¡‡->‹4jN›ò{Ý+8N ÊaÄx¶”rÖ ÃSÔé›5t˜ñ£!™¶•–âæn 1|kX`[Dr¬Æ^™4ÈU@4âAedÅ*èÈå÷;„ïÚå*ûø{9€½ï;ìgaD·¨NákÒ”E‡hô03K†¹…Ö±ÉÂ&jùèÖ"¶ÛS2 ú(mÐ1Öò†"‹Î®¦ªnkIêk®I˜ÉÅWß»·V¢™H(€¡ êáJðøÛ\K ZÖžÛÏ%Ýߎ|CÝÒ|ŸƒòëÒ=ñvvÁöATû=´òŒ°e{… 'ò yú–£¹G6¿äÆ5TíÍ'›¨_dÆúסŸLr»Šr1ßÇEt¥"=lçA+œ)·×N‚s_¢ëõ;žR±Â‡¡ãÃs6±;ݽo–ˆpñÍ£}3¨D7åú]!¡ {. ˜Ûô½Ï·0U`Ý™F,‚ʨaRJ*9æd—ë»$Üç³·Ò{Ûf&”b•Q$$HEBHÁ‚*²¡éñÉüPõ6Óz‡Ó¡`$Õ hf™0fpmYˆ5bÀÙªãPR4±[„°dÓeͪd›¹xïפiîdýš°í! Þ‘AXÐ$kç+džPêêvՔ잯óädÝ=í Ñ@Äå¥Ä"LøzÈÀþÝÜ£X94Þþ$}N½¥¹E–·Hÿ›Ð妖PM¢nµÀÔÑcRà®ç¥:'ƒî$Æ tbûZÌ4ZL;t÷{ÑÒv”ÃÅ ¢Î¶ŠˆrûÌ8<õÊEÂYqö2ÕO—rÅJµ‰tì ‡Òïñ5W÷óNɶNãú0yé‹ÒܺCNŸÀ›;t»aŤMÓˆ–¼N^ÿÄE‘-À˜ Ÿ*ô’4 8{;?˯¥cãÜQÚ+»öí$³ŸŸQ+ôBÃÌûãá$nkkžÉïr„P#.‚Ÿf¿.Ò{:qãíðŒRÆu¸ÅÀ¬<ëé»ÈîÎk[NŒ®.íÀ†žÏ.ذÙJ|î(véMñeLCªw0ÄæÓhpÌk>.³ÄçÛûju ¿ä}.‚{2íÏ„o}ë²÷SÞ´º•ãpÑê£Ô>Ùåc2¯#©ƒ/wÄ7ž\ ¹ÃiÌnÕl¸GcnõvìàOuDóc@žz|m?öUvpÊ:Šâ SDåYaùöOG÷Ð./Ó.‘‹{À0ᢳ½‚¬£Õ>\}ó½O¬ç;øqïQ߇â²{§Ow¼öÞ~Jx1O雷ÒÏ0²ÏÍüßÑxŽâR½GŒN©ö]Ó¦¢*%/˜®õëfå,kZ¬w¶ëÉÛZ™ "&A4iÜôÆEìóPó¡O4(íÛ½ÃIêpÔ)ñ™ð“©óözã뤳êKXᢌ2tuŽóá(xrïâ°èÎZ¬üäØÄLs¬K.3,“¸—æl  ¡ÕãË#" Ÿ…½ãHØ„L83']uÕVPS&!gXÑçŠzys …*ZÚ"Éæ™Ö!òPîb0" AIÒÃL˜‚(Ÿ?»»¦»FµÆ©í@ùg3%Ž ÏäBè*o.rpI >yá ý½ 8…« ‰ª‚"=Z6=£>Å='yyµVîÎÕ®…{ÝpÑFFϽ´Òw›)n(-†™/ôP®M¿GIõd*0W8 ÛnÙÜ•Ä8Ò¨k]æ1E{~s-)B‘Ý3ò°%,µÄW‹?/¡Ÿ£–Çy\3&6&*ÍöGÛ_,:ž«íÉ;ŽÃ»&qÇ‚ÆK«¬)¤ã&¶n ™n¿ufNŽ8y8ˆ‡-G9‚÷ù_ŒhT-ÀÂIYF $*„«R&£¿}g7ƒ˜ÌŸFÀ?Pžô“¸ƒÅ¢±’©)‡ß7 T4 íxäÐá¤Ë'«Ë‘庼(2ˆ]ØlW`Ò…)iŽ1±¤BËDîd$;ÕHp„ìeÈE ËÒŠE>© ¨(=Zl`âCfõCFâÄ5•´Ü„3 )ÄN¬t¨é!äàÈc A;˜X:¡ëxÐ` ¬‘|)ƒ«a×ÂIO«!(‘©úYì#Ë}¬¡´õgÎñw;ºœ†5 ŒË+õô*‘`°ËT¶–Ò¢MÂUZX²Æ´IZ—Šhf¡ª)…¬AÎÙ 2¶ÔGHa“)Ä<}G„ííAC<q¹¸W4I ‚±°Ìƒ[Z3ërzjö2íÑaÓM4áJÚßJ`˜qj íÎ&ÚúNÍ\ s''4èèáÕ!Ñ–C”[Œ2†²Ê8¤aÏ=S~ÛÝUï+’'$U¥:„aŸ ªÜBµÙàZ¨Ó[ä‚ÐCs„Nì ,fIÀ9,…Q× ¡Ä(ˆãÓO’ë‰'*+„b#æC­KßÝ隇©éžì‡‡C£¤çϱ­ ¢¿ÉaCÖæ`'0Ðf4Ò'L+Æ ëi¹ºðÑ‚³M†“â!¦|;ç9ÂŽS–dA~W)E+–B2fx:07âŸ`˜‰0·óÀ‘¡Ù’;—$-9–e^”T·Âº|3W®½)Ãä‹Ëܱm«Í—î2«¿hóÍ{Lò8чJPèã3ºÎÈäx´d–@œ‰ÄNüâàöÊø‚+.(Έ!ŠL»ÿKðÇÖ®&<ƒäÎ3Pî/‰Ù íÜÏΜãN뾈#IéP¿‚Ý*Ô ‚¬st5ÿÔl/Qõf¡BàþÆU›{;åÑwGpËxLBˆXÚ0“ìÜüH¸y»={yrì-ºÅP4oZ°*",ýΰÎå2” ¡å7ÅÜè`q³cJé ËßeKB½>ïL´À%>>öly.ÊR2*¬PÐtVaùp(´u1ôž?' iBÎBA”úthÐ.‚럙•cùšª¾â †^ï [uiɹná-nl­½L*¥ÂP“ò<(_9ÐÞ… +µó::€àÔZb“g…~-ÌYVß÷iYÕî,KÛø¢ âa Êgð>ÕäTœxpx6!%á ʪIŸ¾½¾˜µ-®>Bƒñ;«oNæ—uºÐ=Ô\sÍŸpŸ¡¶GŽ;z£6V;²A’SÇÒ¡mFZ?\²–[w[~‰1^Ëã½Ô1ÌÉU¦©ß¢/JY.œ¬Ò8^H¶vd¢ž—²" 싆S{$›#ÁU²ÅÝË´b’¬]ÛQ›Ìn¯~çï½S}é Á:Wf×qº“ʼÞëù=®ò¶:ü£ˆòt†8ðÍå¥yåZ¤!$‚*içd¼ÃZµù}”ÔÙ‘YCŽˆëæ@´¶É­ÃsÏkNU&PáEA,…EÊéÞ°§ÇLcƘm-•I(ŽØ$ÈamkLv·X\ð†'!ª•†><±è ýJSbëì´N.Õ#eh'wE±Šö¤a«|ñüœtí Õ“Üf†¢Å=OÜ2^q?jçÏ·§ÆöB'®*Äö—ŇÀPµñÍö\HÀˆ Q…+M䉫i 8›áÑŽ‹ˆQûÜA·?ÁÌBî¡#Xú 8DÝU»rC1é‚ìKþU/žúbì~#]fÒbû7æõ^¬Eò'Qz¢•2ÜFSJ/³’Ê?£ªÿaàU`æ;T¦a•œˆý_Ÿáµ€õTA ^VsJ°+…·æÑrѳž Zu7ð²!ÕÄ_-ô´À¼Fì™íµmöAM·J@¤ •7F?’À¼Pý›!}ÊdßCxˆh$&¥Ê>-5~±QÄÒzSŒÄ}bo}|¤ÔüwÙ¦õs‹ë¬o'yƒY½ºM¦KL¯]Èu²Hkþç©y±H£¨LÙYëÂ"N îÌð<Ûˆt䯒ð'µDeÁÐo~Mfø7›Úšj椯‹„ƒ<5:Ô#LŽÎfÅÆØKclþêÌ.ª=ǽ­M}ý~êÏàS´ÙZ3‰#ˆ1£n‡BjV%ª¤l£fP‹v2 MÇ©BÖ9M+†’V Ï<dlc Xe) ƒ¢Y]Ð ` Sÿ£V-©›‰}S“ ¹Mš9sSµœïÅ€Ž@ØŒX@Å^hu¾Wór÷k¿Aóòe‡½§ë†~Báy³Øýwé˜m=74^;5:À½:žØT ×ôˆ‚Qß8nFB!¯¹`·wŸ 9½~´Þšÿ3A,å0Y)À&îû‡‘`%#Z-˜lÏÙá`ÎIEA°S_»ò‰Ul#H .mÝ©j¨’¤Ir`)•-¨"ÐB’$`$¹5„7™¶»5žùHš±a•µÒŒÑ!œ&0ÿ‡2HÛÞD¢Þ,Û8£ÓïÍQDAˆŸäÎ{f|-;ûrÔ«„ É©™­¦ïK;·èq‚ŒsA\næ4.sRS+ÞNõú/ß5Ìk˜Ñ†¬oF ÄõœLUÙEi¡OÜ“¤¼à´šP[ ð„èÏ1Ù q>V/^@÷.d:¸‡çÝåˆéR±¼Ú‘Š¡±(ôfÓ¨Ö³ÂÐrØ’ê‡R¦‹HK© qé†q<!E2ȨqÊÒ_èYŒîaýqÒŒOw…΢ٺ8! wƒª4Ûp¦l )P™FØúªi6§f{=Ð4‰R…¡Ïxv¥ŽF¡#´yk†4Í0EfS^¦Øí¬ðó3UWÖŒ Ç»½»<4í(ÐÙ‘Ò•™/¯¿»¥ºÝyi“Èw|¼KØØ[›ÃBº±Fˆ…©™©KJ¤D¾87rh^Äd„0Áƒ­HNF›CÈBgÀ;ëy%þø÷#4 `ç¨ Ü¥=Û!âÇMd~–’bœšÊ›Éu*ýaæy¬E³E„¯ Ç#k /0Ù@»EÞWù–R !‚vê**.ˆ0mŒŒˆË ¢ÚÖšÝì‘ GPªxTÆcìô¢»~÷©âQaa#KÐÄ8Ã[¡¤‚ÈÒöL`°Å¶ ÓJ‡2wì(ŒæÌÀ“Í JH"RƒÙ*,œ=²‚£°Q╽mˬKTïg<Þè)ÀpÝuÞªzdßtLÙÑÉ­Þ° ¥mE…­®jój¯Ãj|‰ S¹+…² ©l• ‰%]÷(°&¡â³2Ub´P‚„ôѱãŽýœIìäº{ÒP¬î!Ñêø$¾åàu9õæƒò PŒØQŽX;|_ˆìÉjLPyöí7Äøx·žR`ghTZÑ£yzaX ¸bêÏ;wë…²au†àk4$~Äh‹òUg)ÏQaÉ"ŠRà<žÃdç&ØœIÂúœë6C3K¶±t•þkGyíþ··í ž3ºÊ1‚#T‹n³@=l¼Ó º-1­ý$ãœ>bMŒ0mTÞÜùxu—÷¡ƒ#ØpœIUêêþ.ªi oÜ|Àh¢±­=)öÒÕSVäÿ>kÀ0D‘¨–‚‘(È¢—"d3¯«Fflâ“-1ºÌäêM‹NÆë„)}3edžÅ÷š>jM+t—+ø©§CM=Ð÷öBªmœxÌmŸñ®ö£E~˜Ç<6Ú? ë±³’ÿ•ä#£[·îû‰ýFxf•¤€¿—uR!‘DŸè$¢‚@]iÆŽelÜH¤±ëÁwѤ,‘^á&kI¢Éa÷Òáý™BÅØX½ÅÑÕÍxƒ‘‚5Œ_+-¹cÖL ¬NÆ©KÌÚ..˜¯ÅLqZÌöhη½×—ŒûZ}4ìC«öG¯Ü<‘_CGà· £ÉQÛ<]{'“›ž[_œÀšÐc»!7ôïµ6£sÂál”ïÜ"Ò¾Õ:øžRňÈ_$öÚ!È=Àwðn—´¢O›XR{ Ån-}Þ,æÊLëÐÿCøƒó¾Ú}…Çõ†žJ†³"8(úÄÒµ¥­…ÝV|ÿqÜ]VÃÉp3ƒ(œÌ¢añÉÁ|ao•ØU< ÙÅ >¢”ê~ûúΚìXÍt™Š7X‹Up£Èep —à æŠ#3¥ÁV"zZjÚ"ónqð¥D ¼§çïÑzı;až<çrN6aS352ÚX+Ã(Æ¥› xÚT±›žàèè ôÂý²ã0fc|½ÙK¢Ñ³Q`^÷¯Ç[Š£É}¦¥gox…ì  Æ2˜ÓNçi«$ó-Qµ’×ø¾ÞýŸ§ŒØˆ†”(Jž„ÇÆ|§ÕÏCÐŽþÁ™ééé,e”ºûä¯<‘édýRJ•D`ĺÿ6õoS¨¥©ÆkNâðrdƒÄn;;ý݈\ãç k–òb˜õ.=”."r2€Äjì@‚Á¥ÁF çé<)°å Ïî4y~Jq:¥ë<}ìÑoFPH:e5>B¼3Æ»X¢Y»Že†Óo´fú•„]yFzLRä¼1”Ïl¡±2…K""øYÔéÈ3©kÚ²‰!çŒÜéxŸV&Ìà˜å•\ÛÇÖ)ëö·@‘”„Œ61)²4²2'oešQ´Ø˜h~Þ‘¹@/0¨:Ýé\—ˆaš ÄEZ)C"ª©DÑ“3T„ÕÍUT vîªß4\É pB‘ˆCVTdV¤X,ænA( nC• ¢ EBÄ¢XÃLQ`Û3B]L[K¯'‹S‡àFC«îl¿a‹é¾÷ÿ…»e|éI¼éÁ0OÅÑÜÈ_“Ô}XkpóºJU¯?Õ徤üX'ý¦‰D†­›}¾òï“Ó)hÜáÅtZC ï"}}ŽÒè×{óv?¯„ž&'Š^œ!>úxfšôüû ùà˜L& Iõµüùb?bÉÂi‡M¡Uî|G˜4Tßò°j÷6~¥’HÈ$…8w ÅŠS´0Ãf#~Æ›]È‚Æ×sºñ9³ÊÝmäÁ.ï9}‡µµµ;R‡%åöÁÆ d–÷»¯»üŠ&bPáüh¢!ž¥,<ÊÍhº"ÔØÊ‹øß¯—ݸ@ÝcÓñb„Š5cÅQš½¼³s×WÌAJl1@(ÂjOMßøºî/Õì+¯Fh¼ðŽ*¡X #—P:h4 ¼s(B Ì À!ˆbTFZhŒŠ‚aii)d(ÊrÅÕDÇKJƒD†¥<©YhH ) TŠN(,¢€« ‰Z1F(Å-§œÁ É' Ȇ@2ƒ –P$Â!$",S p’*DH(‚°D$¨c$F2 ± ŽD†vÞh¾qÇÓÜ1îm‹‰“©ïÄ@:ðÀ4(:5URªá(„¡B *ð-5»ªÔE:ÜeË!i r j2 "h† D®œ+¼{ƒYІXTv.²b‰Þ`™º"æjå,ÄЃªV;(°¢E&’¡D*A5aMfCBR®y¤$‰ÄÞƒH\Xè <*‘Šbg)r€^» `°º#E! `œs ÀEæjç¦{Ÿ–Ô„„4ÌR*‰ ÁƒX2IRDF-“¡$Ž€—ÕY$Æ›4Øì( ëìÍC}„°qŠ’¤ ØôDÁ°AKR؈’ú0„X¢ŒˆÁ’(ŽÃP%Ô ®ÝºIrl”𙡰PE`ŒŒdˆ¢"Áˆh•©Œ‘ED!dVɱe,( ÊàøYíD’PðI$Fº Œ8pNÌß`4:n7Ø>…©:¥‹®õï±éàØ­ˆ«ÓÃUÞÉ"<_.øÔ¦;åŽñ=‘~Å÷=oµjo#g€rßH± ob·¬ºtãLü¼ìûíŒG5®þ6ŸÂµ×|ôC¿ŠÎ7ÖÖˆ®á«/ ïlœZëø:¯²©Š¥´÷î¼c}8‰›u\jEjmþù íÔz÷§&»W®ßÿ}ÖßF]q'ylÖóÔÚ7´uTNGmY§îï5üVòûü\Ï?!¤r ¡ôÃ|{òvË‘NÖ ˆ!ð 6Æø¶Ž8‰qb©DÖ´EXtƒ®Ç/7ó²€éCK®5å(6ÄV„Ò‰Uc æ’BIF0ƒ ‚Š$’keÏÙ]}êì-[da$‹ÁƒÙ>Nã›4ó}£jNj|˜…¨fDÐ4aB ˆ"€û;£fð`£? 53Ó"CB§ š”Ñà™h¤1®Ÿ£ÝU«8€Óú-5<õæøM§Ñ¼¹Éw—NQ¦‰öo%Ó³‹MVøŒšÚú Ö7N.Ãh “Ø{«»»µg·=b¾¼Q¥Ó¡*ÈO©‚BJ9œìwáGn_º·tƒÝ¼¼}÷ìB¡ ÛÐè¾ÅŽÜkÀÉšU’C€Xe¸ ƒZ%?GAQË5=)Œw‰kcÑf·Ì}¨kZÍ Ó¦™´ÂÇ|é¼ÌS{:t×/N9¶š»2kH †FÉeA&"hìMd§EATLñ‡³Ê ù—EÓë L²Ä¥Yœ@ÝmÒ‚ŒFªbΗ 6QÆs>;+Dý'W¥7TDä.øÆ©WↄèbìzùÏ{óR¢Ø¦Ä3º 8aA¥¢=ŽÒ¯DFßAÖVLŒµãZ\‰­&©jÍvÍtEpÝke¾×«R{ÖôTµI˺ z͉¡¹Ž‹{Þ­O7G­úVB©· :húéƒ;ÌTñÒ6˜ªw8äÆò©{ÞÛÈãßLa^RBº³*8‚Óh³"ëoîÑ'½”1Æ0Å J#§Uê͘å²`6ÝšM[¶Æ”Au¸ÛÁÅÃÒ`)ºÓ-VZó¯ )È·'pd±± Õ]ãPl”µfЃ`F§¢Ì`î—†xŸ‘UÊð(ô …>¤h’H„]º—Q r¦¡Ye-e£Ã:—˜–ä©5÷z6å Ji|-MÐ10ˆXzªEþ¢Ãì£$‹O]ÍTÌW siñ.þNŽyo†fVÖ‘IbÊ“0­EÆ{Ù`¡Œ…VHÁ<{óZÏG–î{ß^_hmçÜ<¹Ò,Íé<ü¹{•`²§«tµW>¢Ô¤&¦•m0ˆQaF4£"fR†mJ£Hpæ³:8ïßmö¦ZÊú´&yÞ¬ÕQÎÕ-¦_ h°›0’H“L"%ÙrlY×ï~eÌ>“ÐùˆT©FÅ{Š3Ðç]‹S° Q¹ç|1V(RJ®aRTæ2ïÝ©]¶mƒð% ­¡E±‡„³sɢޯ2>=®kWr·Gy=²uò:ÿ·^D×^£wœ¤Ì<“N²”Øø8¤yæã5˜ÜÍ´tÓÂé4•‚é롼ˆ¤ºDÊœªML¥,ÛŠUË­&J¢‚KRB2Tòìˆ#6ðm¾8Òe£àÓËcÐwõYipQ:TA½;§S\-ëH<ð»Z¡zéªÃC&/²=ñ‰*ª ì•鑨 íÖâ‚ 7™Ôþ.ÙQÚþª±ëPù,Hõ_²jõµDìÆoϤ@1­CH­ß]¬4ø~®E3C@4-¤bÔ m…½s¶i@ûì™4Ï ræ9o¡Çǵæð1ÓÖ DQs=´œG"/«Ôܽ6¡ ¨%yÂ'g»2Ú§›4Q*“€̧»I4’²™„Dš´J<òÊkTì’ôCdE®SógWh¤X»Þ—ßé‡y¹Ç%ÑJ‘e…Žý_>Â-k\½P$P!;Ñ¢ï,-Ä“h6»]¼¶XË ßh¬—e¦Ì«—ÏB É)‹£ „«O8T!YTÕËÔ° V©F.‹BØÊ”,wÒ\¬ºT°7.öóVî„ç¨ÇQ·Ö¤¡§¨çÐ,«ªY^„™¿ã~8üõzÈNy^qæ–æ£Á¢‰Gê8[ƒÚWŸ,Ì éUHÚ¹u˜k´ô^¶3•Ø­Rˆ37‰€ˆMgfGB‘`~Bõ7˜Žn'á )€îÞž±)·Um+4éñ ƒ‚®JB‡íÚùîŒõújW0Îô)• ¹vµ¢m4eà ÔuTI6‘D 3HR«”Ë"ލ&"‰FD©HÁæ«Uè|D/clU3T<1Ð7H®JÊïÐfûï‚4h¦Ó¡‰ÌfP¾")ŽÒ¸"8Ï‹«ÞU(1²WÕ9¾p-°1.Bô¶!8¦~Ïê“%x±zéZ¢(LƒDWÀMÀè¡TŸ7UˆëÅu.Œ€½]ñͺ ëÄ jîÔØçou3w¦ì›," ºmÑ.CÑ­zê<ÉFfê›rÎFæúÊro€ ØÐ×ô@ñZi-uÝ&Ôˆ ŠÕX‡™•æ»ZØ´ÐDá˜tÆ•—J(¶KµÍPvAŠ¥¹j×QP dèÌ.‰´ ·iÏDYœýøt«ÒØØÈ¦ãAh8¥öVèoE+ £.‘l\®ð…|axÑg†ëÒжQ; ƒCs;lû7Ŷ+Ü ]¶êÈF« · c]­TZ¸©2@˜³ýßM_ÃÍ7Æ6e¬Î;£.ÞU}Á  0iDU~©Py²ãJlwÂV穵kãlämâ|ùãmΰ¾sÏ[L‚ÖËQ[³T*:Ê,GÑCVïŽþ p…bÉT Â)RA‘USºp7ÏM[ç—fšåüTI²onåŠd%Ñ:ij2)·'¶ëgY œ‹^Zl¯Ö"É›¨€ÆÀµfÊË2ÊÚаúJÏ|¶"¨Æ‰ge TW®™¡¤2±t¬˜5DÕµµâÀæª2ÊF Õë.-)%[HwU­vÄ5îh—Ô-·Šjè»N>wL2ÙûCÚ환èñˆ×·Pw1i°GdªaœðØf–X2UQöÂ`¶ „«¨ë½_Ž¥@¼¨ dÓXÚFÕ BTœ¤:«—\G[Úl3÷es­pÂØ•‡KVaÞè• u¹pF†î‰Zg}*(…»5Z ág6Z“4L²g°C’ò™áÍÒµ¼k„¥¶ÕXTc+=‹3žÂƒŸ¢ ÐPŒØìâª!  ¾ü\]äî$àâ‚.˜°£O5E‰ªº óɤ>—BÔKY ÒÑ¥ &"¯ÇÞÓiƦâ÷qá@Mb8F„ñw ]-Ø-syCBê¢È÷OTc×\3.Ã4 T¦«^•é4º¶u%“VlÀr¼éu>ía¨ÞÍ[ü}/ΦÏö'ç'ÍëøUñó^¢¿”æ»,'1c#ÁN@ç(0Éx}×л`¡D¬•QdPƒXÊØ–•©°‘`µ•Œµd È@P¤©d…€B,b#$ ‚H  ÍÙ•ùÌÑUþœ€soð1\‚7“›1ŒsÒJ¿›ù=õ šCXÆi¡ s'q(0ë }“ó~Ù„ÔL1°0é†at\G7qÂÓ½-"̵J‡€C¤!‰åÄã»Þ÷àŠ'>ƒýD ÷y‚dQp-" ß„Dzd0ŒÙ óq€²M¢1Î;h‡™=5@ZÁÔ€ž®¤†Yd¸P:!œ·ƒZ¹‡ÌË`ÐN[ÓΡ>;à>žj¢”³!MIIæIó~Y‘"QVÏ<>c…ð­·M‡ÑK¾þ¯¥PÃxiÆQ·0ÄÛ¦«¤RïÎQ‘Ú÷´õGŒZ‚Óy|ý{`n.WêÅz³TëY¼?WœìeN'ñô—ù9´ ‚øEÀUCÕ¹°ó¹kT¬Û÷æŠ4žh¶Ð^²™œå׋"™Ù°¢m8öJÚm/]ÛPïZ‰‹UÄÁ9[’Þ==­]Usº¹Ö™v¨‘ÂÌíÍßé£P8’©/YeHS* Ìólœb#hvkâBèuÝ¢éž4¬5ÂíõNµ¥©ÎÕwlT(é{1•Ó7Œ¤O¨Èšî³ŽªÙ/Ò½7Ç0ùÙB¡Ãó è™ÚñpÔƒ¤El&ÖuWËM¬=Uò¼D§†Âó»U½'IUÛ c‡\~oùû ¼­ÿ;—ó·o^ƒÛ)U¿|ÍØ®ž™‰‘×ͬ6sú=ȂԿØë=½Ñì›Vg5\fíïjM߈ŒÚm&þùÿF¯˜ƒ3·ê½ém‹G'õ³A^l4`>bôº³ ³Ò“°Ê;uâÔ ä¬Énú˜`UÙÇF½ý>N5ƒȇÙ0ôm–FµM$ðCY•ÈD‚°È=Ò” k $¿æ«º€t—/àÒƒlÈZ®õSô“I˲ÜÀ5͘!ÖOäè&È&€lÆÁ+â”-t®ré=·^Ë¥†²0{Ê´È@;ì´½JY€RJŽ•q¾î¾A­’Ö{Í9¬OÏ’‰¿  Ž‹{„ÁØîÐ ÍV(I|D­Â§¥FIÀ¾Š:YFR€%7ÝÈP0t9T.PØÒù-â$ô6ö‰9LçX¢1;Ú¶/;ÍÆäµ5͈4o4³n¬ôùÉÍE«ój”¥'li#!Égn.e”µ‘J*—V ˆ!k.ø"E>Íþ¿K*6—;ɘÀZÔìÁŠî嬣ž ˆ-æ"ì:³ÕóÄÔŽÄI¹ž›A¤U‰ŒPA”]$_^/Œï³R1FøMHw5A,…4 " aCÅ“U™N…HPŠ ÜÅQć섂I4 %ÛѪ°\¥ˆ€ ( ¡-'m]3qµÊ ÞáÌy¨4[pàW É¢ÄZ•`ØV n*'I¤æpÅãEB—¿¬†Ù" w˜±ÒHR…)θZŒšnƒí ­æß¾{sL¦Ì”£ÈïÕ§Àµ`¶äAâ<²£‘ZQ 3Ђ`0³12`ÀJ%ƒia—=УR…_sòÈ•o@ûœèF`ίRArƒ&fDñre±<ŒO ‡‹çÃCѲ°*nünŽyÀÆ¥GvMöç:7\dC§iŒÆæf37VS7·F*ê†Ùˆ¦ÐÒ0ëlÕç$"*™qF$¢¸I¨&ÊX­í-Ål‘ooŸ¯pÛÞç¿©3Ž›0„è¼] ç(ï\`G_/*õÂAžÆ’ÝŸE ¶–ÑÓíJÇW @ÏÆ‚ØÛ^…ˆÎÕòmLnjqÄѨ!)AE¿j®šˆàZ°àSƒheKÕ#›¯AÔ[ž•lL°µZƒŸ"”ê« ˜¥ Š(º´$ Ä×^·SÖÎ!êo© N™,,(2—º…nŽXrR±œÊŠ’B€$ÆŠ±1 è¢AˆÔãÚcõ×Núã½' ×I‘t ¡ P‘¸%qxVÎí;XÆzÝZ”ó¶f®|ÇÆÂAß B8då# úñ¼ëºðº­3ë=2ëÓöË´IÊí²zÚáÔ×ì½×~L˜eÑâDA‚)]*Xà˜–ºdÞКkÜkRöЃÄÜdée«0©lS„Q–VçÚ~KÉM%EêÂî*VÖª†¥~£â^ïEʸ÷Æÿ–ùjæxè,¶›¦ý&J¸ÂüëÀ(ƒ¸qÈÚlù®<õV9 ²R’¢‰$7ìE¯íºÅ¨wÞ-XE*‹ô±‘9¨è*CÅ+ä¶Õ*<{/Ç ŠáÑ–ïê‰Q˵ÜaÖÀ Üãš\¨³z[”Ê ÈŠBÊY3gvè &‡¶ÜU"–îF8\°µhÇ0ïy¤ És.ˆf$t`Is$kT®‡ „¸ç”ãh$³Èð!¡š¦4ꈈsŠ«ª HkJ¥ú£ OmèÍQ&x« Ù¬GsÉ{v…t (r…@ŸMªà–ÕÞÉdã ¢Édï"Ž;Í"J†)J›:,½‘$! šB`4¥L•é ~2KÂmkfÚ¼†IeÌ/yQPÈ£‹ ú}Nfj4D¹,Êu]•¨í¤Œò‚x"Ф4™ÛkJ¤]RÓT‰"@•2âšyèxµÓ8žÓ]Jâ(¸F"ÃêV §ky-*Á¯wlx•ñÎÖ¼_9 ârí޸ǃÀ»ÙUÑÑê#Q7»ý¾s1kéPØ=ñ‹lÕ¯‚í×{SV¤§IOuzÔè±D)Ø»æé ª‡Á曟…ÅnÊ™'þ ´`k šÈ¡ óOUçõ°Ç¿¦¯ú<–¢|ú^=Px@=Šé3Žä²jùùlìÁ~€Ü aäz¡ƒtsòÄ®ûW¿…R2è|º `ˆH0üæ)Q¼øûÛ§þ;vÅØ~Ïüõ!«à1|Ï;–ç —”mí.0d›Žc2ÀÃ7„$„‰]íã²;s¬ý“æ_q{¾²—o²ˆ™3ÆæôþV÷¬§ø È…¿k}“‡×TÂpþÇáÍ—-èÒÎ×ät_Åô™ ô@·òî‡Î?.äoBÞ¼õ´û¦{ÿtÃii2C [ÞÃáø™ªW´õÝ„ß{Üp5<ª.ƒ÷{êÅ:~Û3kTZò@‹L¥º-CÁúõò5÷°ãªª§ ¨Fè ›-åNÖŠ‘Id’Á€, $€Aãípû¾ÏKÍ ·µX¼ØºÝ{vHŠ.w§BoQ—‹š’I,¸.]y¶§cÂT Ý;î`ê£OX/IIÚŒXc˜¾3m›$ÑfQg’rç’€dÅ 5’°‘A¤ ’ , *F B R"''yä:ƒqö´ÛÎtÌxú¾î¾õ6p×ÂÈçm©ž»'¼É™îܵ߿gâ¿qÄòrK#BŸÚE¤‹»¬îVïÝv·¯EOZ3̯ žjÔÎòŠ’?^Uø‘!†HÍû¤Wqúv¦Øß×f¸Æ{ϳZynûš¶÷‘ímvU5ß—RGƒÐÖBB Ä:Só L¡QÏý­ÅDü¯ÿX};‰×#öô+ñ¹ÀIÄ~ç_{/Ym— bš„ŠªjHÞlKe1­ˆçaHœÛ¯úÙ<šõ *t3¨/!s¦z3yÄ Nˆ¨Äsaç~*q&Ð’€?‘ÅqiºÞaÃ럯R¿1ôù Ö›¼‡µÈò_IÍÏq à÷mµõ±ŠŠOjÁQE¡lm•´j4£*ˆ!h–­µ­l±’¶%£•¯ä~Køÿÿ_—æÎ;ì?T}ßóñOÒ{Ù(.rañÇÇØu`¼®8:q‹!D ˆÉYQB,‘`BTÿ#þpä~ìEsKÊy™s_”å'Ö}¸ÿСÜ'dHüzèT|—" ¤ï[Y×Ǟ˺S-4ìëÜRHæ,=™b•tÛXvòÄ´”¶Œ~_Ü{£ªè,mKÿh*P¾I²ô?ÖG±$ú^¯ñUŒV} ÝÑçN$^* ñq’F@‘a*@´¤XdYVVLÂC$ݰ¥>Lj.pšóòÞßtbF¥9"ø!.ÿÊÔ¥¶Ä;ÎÞøÀFn[óÏÇþ§Öù¼É΢j:RUò7 :d¯‚|bxÑã¼Ö¶£`Fø2i0{PDIõ­ÂDu‘} ×£JŠ ´‚ö¢ÑTRÞÖ‚¹¸¥´é~9_eÎ}n3…aë óÅÂÊóöÌó`¶s{Ïo[ïÑøãË9œ¯'§;»7ÂÝn,}>A¥ìÝA 1œ6Âï{±ÍW„uý³”ÎuUm¯ ë:Võ»06ý—ÅÞ?ËàøÑÇ—½‡aºì4¿“øÀê#-‚dv}¯ÞÔ“Ÿ8ߎü‘ò6|ËÍ?½ïXójUý?m.Ö;3¾3ÚãÂ0-w_hëK·ÏîÑDÞ®Ãèp½oëPóöRßñi¹¯v¥Èõ5Ë"‘;‚ã’~‰Y$iH²¬ €°°+ R i*_¹àJ›pÑn¿}ßZ,:f—éW¡ðÍ£ >OúQ9xsð/õ]+Ö…P4øpì¯Ó]½[±ÊSO[-ó_çbÑÁ‹´¦Ê…-O^N÷®ØLRÅÍpœà¾å÷)c<Ô"2T¬+£‚°R,PA`( Š£$PAP X²((,‹F(E*P¶H –[E• ²QTd¬Š”••`  «ˆÂ#"‹$A‘%b€,PX + Áb²$¬XZP–H¤±"Æ“Œ`1*S⸮ræ};ßq×d½?åJóŽ»KAìï_ïáY¶³7ºCw•]¹´õFaŠ|ÇJ\n-òÍ’c.ĦC¥k"X)ªüäãú99ÿXúC’PDŸ1èïÉ'èHÌÒ(ŸÄùY¨°Ú:<œ’xQ†*¡DE0OècEL8 %")%dU€©ñN‡ã~—ðï«Ç qYj”PÉÛjN‚û<$mºî\Ýàá¢Øü-3îz¿²VïãÝ×Þ7û^~+ Š…Çü8TÕ®z³•“BÆjµ»ÏŸ :oæ£æS#ý>þÊOgº›>wÇÙì¢ÏÃ^Z#+¹ºF’C~ôͲ˜I‰þFvñSí{&{Ü|Q«ã§üo‡ÑDùCV“í o(Yð€ÒÀPÄ@ÒPÆa&cäÈÞÉÈ~=ù!‡; 1êþg[áËCe „c÷>ÚúØ-µhäÿ’Ürv:^ŽMäU#ùüÞvŽìÿ2?7š!ù¦ò-ž¢ëk곟ªŸ°¡Ã 츤¦wêâ|áøW;?ÌÙ˜×øÔNË?Ñ{¾Þ¯ß¶¾ã4†?û›Cäf&}·L—ÿdÈê|ÈEôÅz¥n«Ë†À¯²Sb«0†ú2 Ä–øõ ó8"õÆ¥;‹M¤Íð}@½Õý/"žÊÖVìoÍ%OñFBuaa „ÿ¦Ü@+°šìV¡]îØï2E‘ ±…U#”6_þ.äŠp¡!™ãkJbz2-1.0.0.1/test/data/sample1.ref0000644000000000000000000030061007346545000014465 0ustar0000000000000000÷ƒ’À;è TeX output 1995.07.01:1517‹ÿÿÿÿ gÌ\ ý¯3¤ 2Ì\ ýäÜš‘\Npó°ìKffffcmbx14ºBey•Žïon“d›LËProtÇwot“yp8ˆe˜ImpÒÆlem“enƒŸt“aš>t“ions:ޤÌÍ‘fý>P•ŽïoÒÆlymorphiécc›LËPro‘â!ject“ion˜AnŸäalys•8ˆi“sŽ¡’”E.for–LËGlasgošŽïw“Hask˜ellŽŸ"Û%’¶3óò"V cmbx10»Julian‘ÕTSew®9ardŽ© ’¥îóßêhin˜d“tTh˜e“d؇eAÇs äign“an˜d“impå±lem˜en·¤t˜aÄÍt˜ion“of“aŽ¡‘Hsç r•”s“t-ord؇eš Þr,–ãÎpAÇoå±lymorphiò×c“pro‘ƒŽject¾9ion“anÈalys. e˜r“for“Haskš¾9ell,“capa˜bå±le“of“d؇e-Ž¡‘Hsçtºîect•¾9inßg›²h“eNad˜s”tr'xiò×ctn“eAÇsNs,˜an“d˜tTh“e Þrefore˜suit“a“bå±le˜for˜sup“pAÇort“inßg˜all˜kno“wnŽ¡‘Hsçs”tr'xiò×ctn¾9e•AÇsNs-relašÄÍtºîe“d–ª¹transformÈa˜tš¾9ions.“Dev˜elo˜pm˜en·¤t“culminÈaÄÍtºîeAÇd“in“a“su˜cceAÇsNs-Ž¡‘Hsçful–PÓtr'xial“insš”t•¾9allaÄÍt“ion–PÓin“v¾9e Þr˜s äion“0.19“of“tThš¾9e“Glasgo˜w“Hask˜ell“Compile Þr,Ž¡‘Hsçan•¾9d›º¥tTh“e˜sys”tºîem˜h“as˜b äeen˜us•. eAÇd˜tßo˜anÈalys“e˜a˜ranßge˜of˜Hask¾9ell˜programs,Ž¡‘Hsçincludinßg–Tan“eNarlieš Þr“v¾9e˜r”s äion“of“itâfs. elf,“13000“lin¾9eAÇs“lonßg.ŽŸ"»Ð‘,ó(ÂÖN  cmbx12Ó1‘ €In–ftro`d• u“ct“ionŽŸx‘,óKñ`y cmr10²Thš¸ãe–#ƒpast“d•ÕTecad“e–#ƒh˜as“s1Çeen“a“dramÃŽaÀt˜iñÆc“impro˜v˜em˜en±Çt“in“t•Uh˜e“p#e «rformÃŽance“of“lazyަ‘,fu•Ürnct¸ãionÃŽal›®Žlan“guageGs,˜not•¸ãa“bãŽly˜Hask“ell,˜as˜impãŽlem“en±ÇtÜrors˜h“a“v“e˜dÕTev“elo“p#eGd˜w“ays˜tÜroަ‘,mÃŽap›Ý÷su•¸ãc“h˜lanÜrguageGs˜ecien•±Çt•Uly˜on“t•Üro˜st“oGc•¸ãk˜arc“hitµUect“ureGs.˜Nev“e «rt•Uh“eleGsqs,˜t•Uh“ey˜st“illަ‘,ruÜrn–ÅÅan“ordšÕTe «r“of“mÃŽagnit¸ãud˜e“slo•¸ãw“e «r›ÅÅt•Uh“an˜t•Uh“eGir˜imp#e «raÀt“iv“e˜couÜrn±ÇtµUe «rpartàs,˜an“d,˜w“ors1Çe,ަ‘,it–ÔQloGoks“likš¸ãe“t•Uh˜e“p#e «rformÃŽance“impro˜v˜em˜en±Çtàs“are“t˜ailinÜrg“o .“F‘ÿ*ªurt•Uh˜e «r“increqas1ÇeGs“inަ‘,p•#e «rformÃŽance›V´dÕTep“en•¸ãd˜on˜ n“dinÜrg˜w“ays˜tÜro˜repãŽlace˜co“p“yinÜrg˜b“y˜upGdÜraÀtµUe-in-pãŽlace,˜an“dަ‘,lazy–œ´ev‘ÿqÇaluaÀtš¸ãion“b˜y“str*«iñÆct“ev‘ÿqÇaluaÀt˜ion,“wh˜en“pGo•qs“s#ibãŽle.–œ´A‘œ¢cr*«it˜iñÆcal“elem˜en±Çt“in“t•Uhiš#s“i˜sަ‘,t•Uh•¸ãe›UUs1ÇemÃŽan±Çt“i•ñÆc˜anÃŽalys1ÇeGs˜whi“c•¸ãh˜di#sõTco“v“e «r˜wh“en˜su“c“h˜transformÃŽaÀt“ions˜are˜v‘ÿqÇalid.ŽŸ ‘;Suš¸ãcceGsqsful–PNus1Çe“of“str*«iñÆctn˜eGsqs“an˜d“sh˜ar*«inÜrg“anšÃŽalys1ÇeGs“in“compile «rs“dÕTem˜an¸ãds“care-ަ‘,ful–²cons#idÕTe «raÀtš¸ãion“of“t•Uh˜e“en•Ürgin˜ee «r*«in“g–²constrain±Çtàs“imp•Goqs1Çe“d–²b˜y“s1ÇeparašÀtµUe“compila˜t¸ãion,ަ‘,an•¸ãd›Væb“y˜t•Uh“e˜limitµUeGd˜compušÜrt“in˜g›Være•Gsource“s˜a•¸ãv‘ÿqÇaila“bãŽle.˜Sect“ion‘2˜of˜t•Uhi•#s˜pap“e «r˜exam-ަ‘,in•¸ãeGs›Yòsu“c“h˜constrain±Çtàs˜in˜dÕTet“ail,˜as˜a˜w“ay˜of˜gen“e «raÀt“inÜrg˜us1Çeful˜m“etr*«i•ñÆcs˜wit•Uh˜whi“c¸ãhަ‘,tÜro›ías•qs1ÇeGs“s˜pšGo“s“s#ibilit¸ãie˜s–íin“t•Uh¸ãe“dÕTe˜s#ign“space.“Bas1Çe˜d“on“tš•Uhi#s,“w¸ãe“ouÜrt˜lin¸ãe“in“Sec-ަ‘,t•¸ãion‘3›HÖt•Uh“e˜dÕTe•Gs#ign˜of˜a˜p“oãŽlymorphiñÆc,˜bac•¸ãkw“ards˜str*«iñÆctn“eGsqs˜anÃŽalys1Çe «r˜for˜Hask“ell.ަ‘,Thš¸ãe–­‡anÃŽalys1Çe «r“w˜as“inst˜alleGd“in“Glasgo˜w“Hask˜ell“0.19,“an˜d“shÃŽo˜ws“an“uÜrnpreceGdÕTen-ަ‘,tµUeGd–¹1pr*«iñÆce-p#e «rformÃŽance“raÀtš¸ãio.“Sect˜ion‘4“preGs1Çen±Çtàs“t•Uh˜e“reGsulÜrtàs“of“t•Uhiš#s“exp˜e «r*«imš¸ãen±Çt“an˜dަ‘,concludÕTeGs.–RËAlÜrt•UhšÃŽough“our“pr*«im˜ary“conce «rš#n“i˜s“str*«iñÆctn¸ãeGsqs“anÃŽalys˜i˜s“of“Haskš¸ãell,“t•Uh˜eGs1Çeަ‘,idÕTeqas›H=h•¸ãa“v“e˜widÕTe «r˜ap“pãŽliñÆca“bilit“y˜tÜro˜all˜a“bqstract-in±ÇtµUe «rpret“aÀt“ion˜bas•1ÇeGd˜anÃŽalys“eGs˜forŽŽŽŒ‹* gÌ\ ý¯3¤ 2Ì\ ýäÜš‘R²fu•Ürnct¸ãionÃŽal›âolan“guage•Gs,˜an¸ãd˜shÃŽould˜in±ÇtµUe «re“st˜t•UhÃŽoqs1Çe˜conce «r#n¸ãe“d˜b•¸ãy˜t•Uh“e˜s1ÇeeminÜrgly˜largeޤ ‘Rgap›UUb#et•¸ãw“een˜t•Uh“e˜t•Uh“eory˜an“d˜pract“iñÆce˜of˜a“bqstract˜in±ÇtµUe «rpret“aÀt“ion.Ž© w•‘aReqal,–)Ñusaš¸ãbãŽle“anÃŽalys1ÇeGs“di e «r“f*«rom“protÜrot˜yp#e“impãŽlem˜en±Çt˜aÀt˜ions“in“s1Çev˜e «ral“w˜ays.Ž¡‘RTh¸ãe›N/anÃŽalys•#i“s˜h¸ãas˜t•Üro˜ru“n˜in˜reqasonÃŽa•¸ãbãŽle˜t“im“e˜an“d˜m“emory‘ÿ*ª,˜ev“en˜wh“en˜pre•Gs1Çen±ÇtµUe“d˜wit•UhŽ¡‘Ru•ÜrnreqasonÃŽa¸ãbãŽle›2oinpu“tàs;˜it˜shÃŽould˜\ t"˜pro¸ãp#e «rly˜in±Çt“o˜t•Uh•¸ãe˜exi#st“inÜrg˜compile «r˜f*«ram“e-Ž¡‘Rw¸ãoràk,›xØvi•#s-a-vi“s˜s1Çepara•ÀtµUe˜compila“t•¸ãion,˜an“d˜it˜shÃŽould˜do˜a˜go•Go“d˜job˜for˜imp“ort¸ãan±ÇtŽ¡‘RlanÜrguage–p-feqaÀtš¸ãureGs,“part˜iñÆcularly“suÜrm-of-proGd˜u˜ctàs“t˜yp#ešGs,“p˜oãŽlymorphi#sm“anš¸ãd“high˜e «r-Ž¡‘RordÕTe «r–EÅfuÜrnctš¸ãions.“W‘ÿ*ªe“shÃŽort•Uly“examin˜e“t•Uh˜e“cons1ÇequenceGs“of“t•Uh˜eGs1Çe“constrain±Çtàs“in“som˜eŽ¡‘RdÕTet¸ãail.ަ‘aTh¸ãe–eúmÃŽain“foGcus“of“t•Uhiš#s“pap˜e «r“i˜s“on“global“dÕTeGs˜ign“tradÕTeo s.“Bas1ÇeGd“on“t•Uh¸ãaÀtŽ¡‘Rdi•#sõTcusqs“ion,–gðwš¸ãe“ouÜrt•Ulin˜e“a“part˜iñÆcularly“e ect˜iv˜e“pGoãŽlymorphiñÆc“pro‘Ž8ject˜ion“anÃŽalys1Çe «rŽ¡‘Rfor–¢ Haskš¸ãell,“an˜d“shÃŽo˜w“som˜e“reGsulÜrtàs“f*«rom“it.“Th˜e“anÃŽalys1Çe «r's“dšÕTeGs#ign“d˜et¸ãails“areŽ¡‘Rb•Got•Uh›àëin±ÇtµUe «re“st•¸ãinÜrg˜an“d˜v“oãŽlu•Ürminous,˜bu“t˜not˜ap•¸ãpro“pr*«iaÀtµUe˜h“e• «re,˜so˜refe“renceGs˜tÜro˜moreŽ¡‘Rt•UhÃŽorough›A treqaÀt•¸ãm“en±Çtàs˜are˜giv“en˜t••UhroughÃŽouÜrt˜{˜t“h¸ãe˜ r•s“t˜pGort˜of˜call˜i#s˜proba•¸ãbãŽly˜t•Uh“eŽ¡‘RaŸÿuÜrtš•UhÃŽor's–UUPhD“t˜h¸ãeGs•#i“s‘[Sew94Ž‘8ç].ŽŸ Ué‘R»Arc•®9hitª"ect“ural‘Ü>Ov“e Drview‘-ȲThi•#s›9ôpap“e «r˜dividÕTeGs˜s1Çem•ÃŽan±Çt¸ãiñÆc˜an“alys•#i“s˜systµUems˜in±ÇtÜroŽ¡‘Rt•¸ãw“o›H¢concept“ual˜partàs:˜an˜a“bqstract˜in±Çt•µUeš «rpret“e˜r,–H¢whiñÆcš¸ãh“gen˜e «raÀtµUeGs“recurs#iv˜e“equaÀt˜ionsŽ¡‘Ro•¸ãv“e «r›`™som“e˜domÃŽains,˜an“d˜a˜ xpGoin±ÇtµUe «r,˜whiñÆc“h˜remo“v“eGs˜recurs#ion˜f*«rom˜t•Uh“e˜equaÀt“ions,Ž¡‘Rtš•Uh•¸ãe «reÕTb“y–×5mÃŽakinÜrg“t˜hš¸ãem“us1Çeful“tÜro“compile «rs.“As“usual,“w˜e“require“t•Uh˜e“domÃŽains“tÜro“b#eŽ¡‘Rof–6 nitšµUe“h•¸ãeGigh“t–6tÜro“guaran±Çt˜ee“t˜e «rminÃŽaÀtš¸ãion“of“ xpGoin±Çt˜inÜrg,“an˜d“furt•Uh˜e «r“reGstr*«iñÆct“t•Uh˜emŽ¡‘RtÜro–UUbš#e“di˜str*«ibuÜrt•¸ãiv“e›UUlaÀtŸÿt“iñÆceGs˜tÜro˜mÃŽak“e˜ xpGoin±Çt“inÜrg˜eqas#ie «r.ަ‘aSev¸ãe• «ral›Ð$di e“ren±Çt˜sõTc•¸ãh“em“e•Gs˜for˜ xp“oin±Çt•¸ãinÜrg˜h“a“v“e˜b#een˜pro“p•Goqs1Çe“d.˜Th•¸ãe˜F‘ÿ*ªron±Çt“ie «rsŽ¡‘Ralgor*«it•Uhm–b'clevš¸ãe «rly“expãŽloitàs“monotÜroniñÆcit˜y“tÜro“build“syn±Çt˜act˜iñÆcally“uÜrnique“repreGs1Çen±Çt˜a-Ž¡‘Rt¸ãions,›©t••Uh“us˜tr*«iviali•#s“inÜrg˜t•Uh•¸ãe˜dÕTetµUect“ion˜of˜ xpGoin•±Çtàs.˜In“trošGd•¸ãu“ce˜d›©b“y˜Clac“k˜an“d˜P“eytÜronŽ¡‘RJon•¸ãeGs‘[PC87Ž‘ ],›ž†t•Uh“e˜algor*«it•Uhm˜h“as˜b#een˜m•Uu“c“h˜t“uÜrn“eGd˜o“v“e «r˜t•Uh“e˜y“eqars‘[Mar92Ž‘Z,˜HuÜrn91Ž‘o],Ž¡‘Ran•¸ãd›¾sup“pGortàs˜high“e• «r˜ordÕTe“r˜ xpGoin±Çt•¸ãinÜrg.˜A‘Žs1Çecon“d˜lin“e˜of˜enquiry˜i#s˜t•Uh“aÀt˜of˜lazyŽ¡‘R xpGoin±Çt•¸ãinÜrg,›6”wh“e «re˜t•Uh“e˜ xp•Goin±Çt˜i#s˜only˜compuÜrtµUe“d˜wh•¸ãe «re˜n“ee•GdÕTe“d,˜on˜dÕTemÃŽan•¸ãd.˜Th“eŽ¡‘Rpreci#s1Çe–ù1or*«igins“of“lazy“ xpGoin±Çtš¸ãinÜrg“are“d•ÕTe“baÀt˜a˜bãŽle,–ù1buÜrt“t˜w˜o“eqarly“preGs1Çen±Çt˜aÀt˜ionsŽ¡‘Rare–·Ådš¸ãue“tÜro“t•Uh˜e“Cousotàs‘[CC78Ž‘qÊ]“an˜d“tÜro“Jon˜eGs“an˜d“Mycroft‘[JM86Ž‘N=].“ExtµUens#ionsŽ¡‘RtÜro›ð¨high¸ãe• «r-ordÕTe“r˜ xpGoin±Çt•¸ãinÜrg˜are˜shÃŽo“wn˜b“y˜F‘ÿ*ªe «rguson˜an“d˜Hugh“eGs‘[FH93Ž‘!],˜an“d˜b“yŽ¡‘RRošqs1Çen¸ãd•Üra“hl‘[Ro˜s93Ž‘j­].–ΆThš¸ãe“w˜oràk“of“Hankin“an˜d“Le“M˜‘ûGet˜ay˜e «r“on“\lazy“t˜yp#eGs"‘[HM94Ž‘ª¯]Ž¡‘Ri#s–UUalso“relaÀtµUeGd.ަ‘aIn–8×t•Uhiš#s“pap˜e «r“wš¸ãe“t˜ak˜e“a“t•Uhird“ap˜proac˜h:“compuÜrt˜aÀt˜ion“of“compãŽletµUe“ xpGoin±ÇtàsŽ¡‘Rb¸ãy–4öus#inÜrg“a“tšµUe «rm“rewr*«it˜e“syst˜em“tÜro“transform“s1ÇemÃŽanš±Çt¸ãiñÆcally“equiv‘ÿqÇalen˜t“tµUe «rms“tÜroŽ¡‘Rsynš±Çt•¸ãact“iñÆcally‘8|idÕTen˜t“iñÆcal–8|normÃŽal“forms.“Cons1Çel“dÕTe•GsõTcr*«ibš#e“s–8|a“s˜impãŽle“rewr*«itµUe «r“for“t•¸ãw“o-Ž¡‘Rp•Goin±Çt›ÚulaÀtŸÿt¸ãiñÆce“s˜us1Çe“d˜in˜Y‘ÿ*ªale˜Hask•¸ãell‘[Con91Ž‘Ç!],˜an“d˜t•Uh“e˜tµUec“hnique˜w“as˜extµUen“dÕTeGd˜tÜroŽ¡‘Rot•Uh•¸ãe «r›ëËlaÀtŸÿt“iñÆceGs˜in‘[Sew94Ž‘8ç],˜Sect“ion˜5.˜Rewr*«itµUe-bas1Çe•Gd˜ xp“oin±ÇtµUe• «rs˜cannot,˜in˜gen¸ãe“ral,Ž¡‘RsoãŽlv•¸ãe›UUhigh“e• «r-ordÕTe“r˜equaÀt•¸ãions,˜buÜrt,˜as˜w“e˜sh“all˜s1Çee,˜t•Uhi#s˜m•ÃŽay˜not˜m“aÀtŸÿtµUe «r˜m•Uu•¸ãc“h.ަ‘aNošGc•¸ãk“e «r‘[No˜c93Ž‘8è]›ѶshÃŽo“ws˜a˜w“oràkinÜrg˜anÃŽalys•1Çe «r,˜bas“e•Gd˜on˜\a¸ãbqstract˜re“d•¸ãu“ct“ion",Ž¡‘Rwhš¸ãe• «re‘‚8tµUe“rm-rewr*«it˜inšÜrg–‚8i#s“us1ÇeGd“t˜o“execu˜tµUe“t•Uh¸ãe“program“us#in˜g“somš¸ãe“a˜bqstract“s1Çe-Ž¡‘RmÃŽan±Çt¸ãiñÆcs.–dBy“comparš*«i#son,“our“tµUe «rm-rewr˜it¸ãinšÜrg“i#s“us1ÇeGd“t˜o“dÕTetµUect“ xpGoin±Çtàs,“an¸ãdŽ¡‘Rt•Uh¸ãe «re–-viš#s“a“cleqar“di˜st•¸ãinct“ion‘-vb˜et“w“een›-vt•Uh“e˜a“bqstract˜in±ÇtµUe «rpret“aÀt“ion˜an“d˜ xpGoin±Çt“inÜrgŽ¡‘Ract•¸ãivit“ieGs.ަ‘aThš¸ãe–˜ preci#s1Çe“nÃŽaÀt˜ure“of“a˜bqstract“in±ÇtµUe «rpret˜aÀt˜ions“i#s“dÕTetµUe «rmin˜eGd,“nÃŽaÀt˜urally‘ÿ*ª,“b˜yŽŽŽŒ‹: gÌ\ ý¯3¤ 2Ì\ ýäÜš‘,²t•Uh•¸ãe›¾štransformÃŽaÀt“ion˜tÜro˜b#e˜sup“p•GortµUe“d.˜On•¸ãe˜part“iñÆcularly˜impGort“an±Çt˜c“h“aractµUe «r*«i#sa-ޤ ‘,tš¸ãion–ZÄi#s“t•Uh˜e“laÀtŸÿt˜išñÆceGs“tÜro“whi˜cš¸ãh“di e «ren±Çt“t˜yp#eGs“are“mÃŽap˜p#eGd.“In“t•Uh˜e“s#impãŽleGst“cas1Çe,Ž¡‘,all–RŸnon-fuÜrnctš¸ãionÃŽal“t˜ypš#eGs“could“b˜e“mÃŽap¸ãp˜ešGd“tÜro“a“t•¸ãw“o-p˜oin±Çt›RŸlaÀtŸÿt“iñÆce,˜wit••Uh˜t“h¸ãe˜pGoin±ÇtàsŽ¡‘,repreGs1Çen±Çtš¸ãinÜrg–Rpno“dÕTemÃŽan˜d“an˜d“w˜eqak“h˜eqad“normšÃŽal“form“(WHNF)‘RodÕTem˜an¸ãd“reGsp#ect-Ž¡‘,ivš¸ãely–¡šin“str*«iñÆctn˜eGsqs“anÃŽalys•#i“s.–¡šF‘ÿ*ªor“a“s#impãŽle“sh˜ar*«inÜrg“anÃŽalys•#i“s,–¡šw˜e“migh˜t“us1Çe“a“3-Ž¡‘,pGoin±Çt›!äc•¸ãh“ain,˜dÕTenot“inÜrg˜no˜refe «renceGs,˜exact•Uly˜on“e˜refe «rence,˜an“d˜t“w“o˜or˜moreŽ¡‘,refe «renceGs.–¿óSimpãŽle“a•¸ãbqstract“ions›¿ólik“e˜t•Uh“eGs1Çe˜are˜rouÜrt“in“ely˜us1ÇeGd˜in˜exi#st“inÜrg˜Hask“ellŽ¡‘,compile «rs‘[Con91Ž‘Ç!,‘¬úPJ93Ž‘žÅ].–¬úThš¸ãe“s#impãŽliñÆcit˜y“of“t•Uh˜e“a˜bqstract˜ions“mÃŽak˜eGs“t•Uh˜eGsš1Çe“anÃŽalys˜eGsŽ¡‘,c•¸ãh“eqap›UUan“d˜relia“bãŽle,˜so˜w“e˜sh“all˜not˜cons#idÕTe «r˜t•Uh“em˜furt•Uh“e «r.ŽŸ +«‘;A‘¬ªmore›¬ÁpGo•¸ãw“e «rful˜anÃŽalys•#i“s˜migh•¸ãt˜aÀtŸÿtµUempt˜tÜro˜giv“e˜dÕTet“aileGd˜informÃŽaÀt“ion˜a“bGouÜrtŽ¡‘,fu•Ürnct¸ãions›Á?dÕTeqalin“g˜wit•Uh˜stru•¸ãct“ureGd˜t“yp#eGs˜su“c“h˜as˜li#stàs,˜treeGs,˜or˜wh“aÀtµUev“e «r˜program-Ž¡‘,mš¸ãe «rs–7^care“tÜro“dÕTe n˜e.“LaÀtŸÿt˜iñÆceGs“a˜bqstract˜inÜrg“su˜c˜h“t˜yp#eGs“gro˜w“in“accordÜrance“witš•Uh“t˜h¸ãeŽ¡‘,compãŽlexitš¸ãy–apof“t•UhÃŽoqs1Çe“t˜yp#eGs,“so“t•Uh˜e «re“iš#s“no“arbitrary“cu•Ürt“o –appGoin±Çt“b˜ey•¸ãon“d‘apwhiñÆc“hŽ¡‘,all–LDdÕTetš¸ãails“are“ignoreGd.“In“ot•Uh˜e «r“w˜ords,“t•Uh˜e «re“iš#s“a“pGo•qs“s˜ibilit¸ãy–LDof“s1ÇeeGinÜrg“arbitrar*«ilyŽ¡‘,f•#ar›œô\ins“idÕTe"˜dÜraÀt•¸ãa˜stru“ct“ureGs.˜Th“e˜do“wns•#idÕTe˜i“s˜t••Uh¸ãaÀt˜t“h•¸ãeGs1Çe˜laÀtŸÿt“iñÆceGs˜can˜an“d˜do˜getŽ¡‘,vš¸ãe «ry–&Çlarge,“so“t•Uh˜e“anÃŽalys•#i“s‘&Çb“ecom˜eGs‘&Çexp“ens“iv˜e.–&ÇIn“t•Uhi#s“s•1Çens“e,‘&Çs“em•ÃŽan±Çt˜iñÆc›&Çan“alys•#i“s˜i“sŽ¡‘,a–”Qpartš¸ãiñÆcularly“in±Çtract˜a˜bšãŽle“prob˜lem,“b#ecašŸÿus1Çe“t•Uh¸ãe“laÀt˜tš¸ãiñÆce“s#izeGs“an˜d“t••Uh“us–”QamouÜrn±Çt“ofŽ¡‘,e ort–*KrequirešGd“can“gro¸ãw“exp˜on•¸ãen±Çt“ially–*Kwit•Uh“compãŽlexitš¸ãy“of“t˜yp#eGs.“F‘ÿ*ªor“exampãŽle,“ifŽ¡‘,an–&itµUem“of“t¸ãypš#e“Á(Int,–?ýInt,“Int)–&²i˜s“mo•GdÕTelle“d–&bš¸ãy“a“9“pGoin±Çt“laÀtŸÿt˜iñÆce,“(2–ÛWó !",š cmsy10¸“²2“¸“²2)Ÿÿó O!â…cmsy7·?Ž‘À²,Ž¡‘,addinšÜrg–B³just“on¸ãe“more“ÁInt“²t˜o“t•Uhš¸ãe“t˜upãŽle“e ect˜iv˜ely“douš•UbãŽleGs“t˜hš¸ãe“laÀtŸÿt˜iñÆce“s#ize,“giv-Ž¡‘,inÜrg›[f(2–畸“²2“¸“²2“¸“²2)Ÿÿ·?Ž‘À².˜Th•¸ãe˜coqstàs˜of˜high“e• «r˜ordÕTe“r˜s1Çem•ÃŽan±Çt¸ãiñÆc˜an“alys1ÇeGs˜are˜almoqstŽ¡‘,legen¸ãd•Ürary‘ÿ*ª,›wkbu“t˜ev¸ãen˜ r•s“t˜ordÕTe «r˜anÃŽalys1Çe•Gs˜can˜b#ecom¸ãe˜exce“sqs•#iv¸ãely˜exp“ens“iv¸ãe.˜Get-Ž¡‘,t•¸ãinÜrg›…reqasonÃŽa“bãŽle˜p#e «rformÃŽance˜som“et“im“e•Gs˜require“s˜\w•¸ãoràk˜limit“inÜrg"˜{˜t•Uhro“winÜrg˜aw“ayŽ¡‘,dÕTet•¸ãail›UUwhiñÆc“h˜a“bqstract˜in±ÇtµUe «rpret“aÀt“ion˜w“ould˜ot•Uh“e «rwi#s1Çe˜piñÆc“k˜up.ŽŸ!@½‘,Ó2‘ €Cons ™train–ftÔËs–€on“via bÙ™le“dÆfe`s0ignsŽŸÚW‘,»2.1‘ üSepara•¶ftª"e‘ÕTCompila“t®9ionŽŸÚW‘,²Cur*«iously–Ÿóenough,“s1ÇeparašÀtµUe“compila˜tš¸ãion“i#s“t•Uh˜e“biggešGst“s#inÜrgle“source“of“dÕTe˜s#ignŽ¡‘,constrainš±Çtàs.‘O©A‘O§con•¸ãv“enien˜t›O©w“ay˜t•Üro˜view˜a˜m•Uul“t•¸ãi-moGd“ule˜program˜i#s˜as˜a˜directµUeGd,Ž¡‘,ro•GotµUe“d,›úúp“o•qs“s•#ibãŽly˜cycliñÆc˜graph,˜wit•Uh˜arcs˜re ect¸ãinÜrg˜impGort˜dšÕTep“en•¸ãd˜encieGs,›úút•Uh“e˜ÁMainŽ¡‘,²moGdš¸ãule–GåaÀt“t•Uh˜e“\tÜro˜p",“an˜d“t•Uh˜e“Hask˜ell“ÁPrelude“²aÀt“t•Uh˜e“bGotŸÿtÜromŸü^ÿóÙ“ Rcmr7±1ŽŽ‘|s².“CompilaÀt˜ion“of“aŽ¡‘,mo•Gd¸ãule›³.ÁM‘³²caŸÿus1Çe“s˜t••Uh¸ãe˜compile «r˜tÜro˜reqad˜t“h•¸ãe˜source˜tµUext˜of˜ÁM‘³²an“d˜in±ÇtµUe «rf#ace˜ leGs˜ofŽ¡‘,mo•Gdš¸ãule“s‘‹Ðimm˜e“diaÀtµUely–‹Ðb#elo˜w“ÁM²,“an˜d“emit“coGdÕTe“an˜d“inš±ÇtµUe «rf#ace“ leGs“for“ÁM².“In˜tµUe «rf#aceŽ¡‘, lešGs–Êare“us1Çe˜d“bš¸ãy“t•Uh˜e“compile «r“tšÜro“comm•Uu˜niñÆcaÀtµUe“reGsul˜tàs“of“s1ÇemšÃŽan±Çt¸ãiñÆc“an˜alys1ÇeGs“acro•qs“sŽ¡‘,mo•Gdš¸ãule‘Ðb“ou•Ürn˜d“ar*«ieGs.–ÐIn“t•Uh˜e“a˜bqs1Çence“of“informÃŽaÀt˜ion“a˜bšGouÜrt“imp˜ortµUe˜d“en±Çt•¸ãit“ie˜s,‘Ðt•Uh“e «reŽ¡‘,i#s–âìalwš¸ãays“a“safe“asqsuÜrmpt˜ion“whiñÆc˜h“can“bš#e“mÃŽadÕTe.“Thi˜s“f*«ram•¸ãew“oràk›âìimp•Goqs1Çe“s˜s1Çev¸ãe «ralŽ¡‘,limit•¸ãaÀt“ions:ŽŸ®¬‘2@»{ŽŽŽ‘=²Thš¸ãe–tin±ÇtµUe «rf#ace“ leGs“ough˜t“tšÜro“b#e“limitµUeGd“t˜o“a“reqasonÃŽaš¸ãbãŽle“s#ize,“ot•Uh˜e «rwi#s1Çe“t•Uh˜eŽ¡‘=compile «r–\fmÃŽay“sp#enš¸ãd“a“lot“of“t˜im˜e“reqadinÜrg“t•Uh˜em.“F‘ÿ*ªor“exampãŽle,“Glasgo˜w“Hask˜ellŽ¡‘=0.19's–®/ÁPrelude“²in±ÇtµUe «rfš#ace“i˜s“a¸ãbGoušÜrt“100k“lon˜g,“an¸ãd“reqadin˜g“it“s#igni can±Çt•Uly“slo¸ãwsŽ¡‘=compile «r›UUst•¸ãart“up˜for˜smÃŽall˜mošGd“ule˜s.Ž‘,Ÿ Ù‰ff8çÏŸ LÍ‘Ÿü-=ó)¹Aa¨cmr6Ô1ŽŽ‘ ?üÐIt–Ti äs“con•¾9v“enien·¤t–Ttšßo“asNsu˜mš¾9e“all“mo•AÇd˜ule“s›Timp“ort˜tTh¾9e˜ó1ߤN cmtt9ÜPreludeÐ.ŽŽŽŒ‹*^ gÌ\ ý¯3¤ 2Ì\ ýäÜš‘X@»{ŽŽŽ‘c²InformÃŽaÀtš¸ãion–˜×only“ o˜ws“up˜w˜ards,“tÜro˜w˜ards“ÁMain².“F‘ÿ*ªor“queGst˜ions“of“t•Uh˜e“formޤ ‘c\hÃŽoš¸ãw–Q6i#s“en±Çt˜it˜y“X‘PôgoinšÜrg“t˜o“b#e“us1ÇeGd?",“wš¸ãe“also“n˜eeGd“informÃŽaÀt˜ion“ o˜ws“do˜wn˜w˜ardŽ¡‘cf*«rom‘UUÁMain².Ž¡‘X@»{ŽŽŽ‘c²T‘ÿ*ªo–Äâcompile“a“moGdš¸ãule“ÁM²,“it“shÃŽould“suce“tÜro“reqad“t•Uh˜e“in±ÇtµUe «rf#acešGs“for“mo˜d¸ãule˜sŽ¡‘cimm•¸ãeGdiaÀtµUely›Öçb#elo“w˜ÁM².˜W‘ÿ*ªe˜ce «rt“ainly˜w“an±Çt˜tÜro˜a“v“oid˜reqadinÜrg˜all˜t•Uh“e˜in±ÇtµUe «rf#aceGsŽ¡‘cin–½t•Uhš¸ãe“do˜wn˜w˜ard“cloqsure“of“ÁM²:“for“ÁMain²,“t•Uh˜aÀt“could“m˜ešqan“re˜adinÜrg“t•Uhš¸ãe“en±Çt˜ireŽ¡‘cs1Çet–UUof“in±ÇtµUe «rf#aceGs.Ž©Žû‘R»Mu×t•®9ually›èÕrecur-s(äiv“e˜mošQÇd“ule˜s‘<;²Exi#st•¸ãinÜrg›DæimpãŽlem“en±Çt“aÀt“ions˜dÕTeqal˜wit••Uh˜m“uÜrt¸ãuallyŽ¡‘Rrecurs#iv•¸ãe‘cÆmošGd“ule˜s–cÆin“t•¸ãw“o›cÆw“ays.˜On“e˜i#s˜tÜro˜compile˜all˜mošGd“ule˜s–cÆin“a“group“tÜro-Ž¡‘Rget•Uhš¸ãe «r,–Ãa“cleqan“soãŽluÜrt˜ion,“as“wit•Uh“Y‘ÿ*ªale“Hask˜ell's“\compilaÀt˜ion“uÜrnitàs".“Th˜e“ot•Uh˜e «rŽ¡‘Ri#s–™ptÜro“compile“eqacš¸ãh“moGd˜ule“in“t•Uh˜e“group“s1ÇeparaÀtµUely‘ÿ*ª,“uÜrn±Çt˜il“in±ÇtµUe «rf#ace“ leGs“st˜a˜bili#s1Çe,Ž¡‘RdÕTenot¸ãinÜrg–¥La“ xešGd“p˜oin±Çt.“Thi#s“mš¸ãeqans“t•Uh˜ašÀt“a˜t“leqast“onš¸ãe“moGd˜ule“will“h˜a˜v˜e“tÜro“b#eŽ¡‘RcompileGd–?Nwit•Uh“ze «ro“s1ÇemÃŽan±Çtš¸ãiñÆc“kno˜wleGdge“of“t•Uh˜e“ot•Uh˜e «rs,“witš•Uh“t˜h¸ãe“compile «r“mÃŽak-Ž¡‘RinÜrg›„{w¸ãor•s“t-cas1Çe˜asqsuÜrmpt•¸ãions.˜Th“e˜upqshÃŽot˜of˜t•Uhi•#s˜i“s˜t•Uh•¸ãaÀt,˜for˜s1ÇemÃŽan±Çt“iñÆc˜anÃŽalys1ÇeGsŽ¡‘Rin•¸ãv“oãŽlvinšÜrg‘UU xpGoin±Çt“in˜g,›UUt•Uh“e˜ xp•Goin±Çtàs˜b#e“in•Ürg˜compu“tµUe•Gd˜mÃŽay˜b#e˜su•Ub“o•¸ãpt“imÃŽal.ަ‘R»2.2‘ üCompßJletª"e–ÕTor“minimº}al“fu×nct®9ion“graphs?ŽŸŽû‘R²FixpGoin±Çt•¸ãinÜrg›1]b“y˜minimÃŽal˜fuÜrnct“ion˜graphsŸü^ÿ±2ŽŽ‘ ­Ð²(MF“Gs)˜builds˜t•Uh“e˜minimÃŽal˜s1Çet˜ofŽ¡‘Rargu•Ürmš¸ãen±Çt-reGsul“t–ÖŒpairs“ó  b> cmmi10µG“²n˜ee•GdÕTe“d–ÖŒtÜro“ev‘ÿqÇaluaÀtµUe“t•Uh˜e“ xpGoin±Çt“aÀt“a“sp#eci c“arguÜrm˜en±ÇtŽ¡‘RµxŸÿót}\Êcmti7ÅinitŽ‘ ¹².–c/Thš¸ãe“init˜ial“graph“i#s“¸f²(µxŸÿÅinitŽ‘ ¹µ;‘ª¨¸>²)¸gŸü^ÿ±3ŽŽ‘|s².“A˜t“eqac˜h“itµUe «raÀt˜ion,“reGsulšÜrtàs“for“all“argu˜m¸ãen±ÇtàsŽ¡‘Rin–“4t•Uhš¸ãe“curren±Çt“graph“µGŸÿó 0e—rcmmi7´nŽ‘ ²²are“re-ev‘ÿqÇaluaÀtµUeGd,“givinÜrg“µGŸÿ´n±+1Ž‘‘².“Wh˜en“an“ap˜pãŽliñÆcaÀt˜ion“ofŽ¡‘Ra–ùAfušÜrnct¸ãion“t˜o“som¸ãe“argu˜m¸ãen±Çt“µx“²i#s“encou˜n±ÇtµUe «reGd,“t•Uhš¸ãe“exi#st˜inÜrg“graph“µGŸÿ´nŽ‘j¿²i#s“s1Çeqarc˜h˜eGdŽ¡‘Rfor–sÛa“corre•Gsp“on¸ãdinšÜrg‘sÛre“sul˜t.–sÛIf“tš•Uh¸ãaÀt“µx“²i#s“not“preGs1Çen±Çt,“t˜hš¸ãe“reGsulÜrt“i#s“t˜ak˜en“as“¸>“²an˜dŽ¡‘Rt•Uhš¸ãe–¼9pair“(µx;‘ª¨¸>²)“i#s“ins1Çe «rtµUeGd“in±ÇtÜro“µGŸÿ´n±+1Ž‘‘².“Th˜e“pro•Gce“s•qs›¼9rep#e“aÀtàs˜uÜrn±Çt•¸ãil˜µG˜²st“a“bili#s1ÇeGs,Ž¡‘Rwhš¸ãe «reupGon–UUµG²(µxŸÿÅinitŽ‘ ¹²)“dÕTeliv˜e «rs“t•Uh˜e“requireGd“v‘ÿqÇalue.“As“an“exampãŽle,“cons#idÕTe «r:Ž©+DýŸç¹’Š#xóý': cmti10ÄfŽ’š¾Ñ²::ŽŽ’¥R»[»2‘þ¢_Ÿÿ·?Ž‘„¿Ÿó2?ŽŽ‘ ‹Ø¸!‘Ç»2‘þ¢_Ÿÿ·?Ž‘„¿Ÿó2?ŽŽ‘ ÄÀ²]ŽŽŸ Y–Ÿ¨’Š#xÄf‘å¬xŽ’š¾Ñ²=ŽŸëô’¥R»óú±u cmex10«8ŽŸ ’¥R»<ŽŸ ’¥R»:ŽŽŸóæd’¯œ°¸?Ž’7ÊsÄifŽ’BÒ?µx–Dz=“¸?ŽŽ¡’¯œ°Älift–òز(Älift“²(»0²))Ž’â¹È¸u‘㈲(ÄliftŽ‘ õ«²(¸?²)–8à¸t“²(µf‘Ú§¸?²))Ž’7ÊsÄifŽ’BÒ?µx–Dz=“ÄliftŽ‘¼Ã²(¸?²)ŽŽ¡’ظàµx–㈸u“²(ÄliftŽ‘ õ«²(¸?²)–8à¸t“²(µf‘Ú§x²))Ž’7ÊsÄotherwiseŽŽŽŽŽŽŽŽŽ¦‘R²Givš¸ãen–æµxŸÿÅinitŽ‘Þv²=‘%_ÄliftŽ‘ ²(¸?²),“w˜e“h˜a˜v˜e“µGŸÿ±0Ž‘¡Ò²=‘%_¸f²(ÄliftŽ‘ õ«²(¸?²)µ;‘ª¨¸>²)¸g².“Ev‘ÿqÇaluaÀt˜inÜrg“(µf‘8îÄliftŽ‘.™²(¸?²))“giv˜eGsŽ¡‘RreGsulÜrt‘ÁêÄlift–òز(Älift“²(»0²))Ž‘4½danš¸ãd–Áêa“n˜ew“pair“(¸?µ;›ª¨¸>²),“so“µGŸÿ±1Ž‘C‹²=‘Ǹf²(¸?µ;˜¸>²)µ;˜²(ÄliftŽ‘ õ«²(¸?²)µ;˜Älift–òز(Älift“²(»0²)))¸g².Ž¡‘RItµUe «raÀtš¸ãinÜrg–4Üagain“giv˜eGs“µGŸÿ±2Ž‘ b¾²=‘æK¸f²(¸?µ;–ª¨¸?²)µ;“²(ÄliftŽ‘ õ«²(¸?²)µ;“Älift–òز(Älift“²(»0²)))¸g–4ܲan˜d“µGŸÿ±3Ž‘ b¾²=‘æKµGŸÿ±2Ž‘|s²,“soŽ¡‘RµG²(µxŸÿÅinitŽ‘ ¹²)–Ç=“ÄliftŽ‘¼Ã²(ÄliftŽ‘ õ«²(0)).Ž¡‘aIn–Dtš•Uhi#s“exampãŽle,“t˜hš¸ãe“requireGd“answ˜e «r“w˜as“obt˜ain˜eGd“b˜y“ev‘ÿqÇaluaÀt˜inÜrg“µf‘Wª²aÀt“t˜w˜oŽ¡‘RoušÜrt–Æof“itàs“four“argu˜m¸ãenš±Çt“pGoin˜tàs.“Whš¸ãen“t•Uh˜e“arguÜrm˜en±Çt“laÀtŸÿt˜iñÆceGs“con±Çt˜ain“t•UhÃŽousan˜dsŽ¡‘Rof–]­pGoin±Çtàs,“t•Uhš¸ãe“hÃŽo˜pš#e“i˜s“t•Uhš¸ãaÀt“only“a“t˜in˜y“minor*«it˜y“of“argu•Ürm˜en±Çt-reGsul“t–]­pairs“n˜eeGd“tÜroŽ¡‘Rb#e‘UUcompuÜrtµUeGd.Ž¡‘aMF•¸ãGs›h>ac“hiev“e˜\lazy"˜ xpGoin±Çt“inÜrg˜b#ecaŸÿus1Çe˜t•Uh“ey˜mÃŽak“e˜expãŽliñÆcit˜t•Uh“e˜dšÕTep#en“d˜enceŽ¡‘Rb#et•¸ãw“een–?inpušÜrt“an¸ãd“ou˜tʪpu˜t“pGoin±Çtàs.“Notš¸ãiñÆce“hÃŽo˜w“t•Uh˜e“algor*«it•Uhm“i#s“limitµUeGd“tÜro“ r•s“tŽ‘RŸŸ«‰ff8çÏŸ LÍ‘Ÿü-=Ô2ŽŽ‘ ?üÐA–Tfußnctš¾9ion's“graph“i äs“no“more“tTh˜an“a“coå±llect˜ion“of“argu•ßm˜en·¤t-reAÇsul“t–Tpair”s“for“it.ŽŸ ‘Ÿü-=Ô3ŽŽ‘ ?üó,©±Ê cmsy9×>–TÐif“m•Èaxim“al–T xpšAÇoin·¤tâfs“are“sough¾9t,“×?“Ðfor“minimÈal“ xp˜oin·¤tâfs.ŽŽŽŒ‹@¨ gÌ\ ý¯3¤ 2Ì\ ýäÜš‘,²ordÕTe «r–ª6fuÜrnctš¸ãions:“high˜eš «r“ordÕTe˜r“ xpGoin±Çtš¸ãinÜrg“w˜ould“require“compar*«inšÜrg“compãŽletµUe“fu˜nc-ޤ ‘,t•¸ãion›ƒ‚repreGs1Çen±Çt“aÀt“ions,˜whiñÆc“h˜i•#s˜preci“s1Çely˜wh•¸ãaÀt˜lazy˜ xpGoin±Çt“inÜrg˜i•#s˜dÕTešGs“ign¸ãe˜d–ƒ‚tÜro“a•¸ãv“oid.Ž¡‘,Nev•¸ãe «rt•Uh“eleGsqs,›‡Åb“y˜extµUen“dinÜrg˜t•Uh“e˜not“ion˜of˜dšÕTep#en“d˜ency›‡Åb#et“w“een˜inpuÜrtàs˜an“d˜ou•Ürtʪpu“tàs,Ž¡‘,F‘ÿ*ªe «rguson– anš¸ãd“Hugh˜eGs‘[FH93Ž‘!]“h˜a˜v˜e“su˜cceGsqsfully“gen˜e «rali#s1ÇeGd“MF˜Gs“tÜro“w˜oràk“in“t•Uh˜eŽ¡‘,high¸ãe• «r›T’ordÕTe“r˜cas1Çe,˜callin•Ürg˜t•Uh¸ãem˜concretµUe˜d“aÀt•¸ãa˜stru“ct“ureGs˜(CDSs),˜an“d˜Roqs1Çen“d•Üra“hlŽ¡‘,repšGortàs–UUs#imilar“re˜sulÜrtàs‘[Roqs93Ž‘j­].Ž¡‘;F‘ÿ*ªuÜrnct•¸ãionÃŽal›6t“yp#eGs˜a“bqstract˜tÜro˜dom•ÃŽains˜wit•Uh˜so˜m“an•¸ãy˜pGoin±Çtàs˜t•Uh“aÀt˜lazy˜ xpGoin±Çt-Ž¡‘,inÜrg–pÂcan“mÃŽakš¸ãe“an“enormous“di e «rence“for“high˜eš «r“ordÕTe˜r“anÃŽalys•#i“s.–pÂF‘ÿ*ªe˜rguson“an¸ãdŽ¡‘,Hugh•¸ãeGs›UUgiv“e˜ gureGs˜for˜t•Uh“e˜f#amous˜Áfoldr²-Áconcat˜²exampãŽle:Ž©‘³‘;¿÷Áfoldr–?ý::“(a“->“b“->“b)“->“b“->“[a]“->“bŽ¡¡‘;¿÷foldr–?ýf“a“[]“=“aŽ¡‘;¿÷foldr–?ýf“a“(x:xs)“=“f“x“(foldr“f“a“xs)Ž¡¡‘;¿÷concat–?ý::“[[a]]“->“[a]Ž¡‘;¿÷concat–?ý=“foldr“(++)“[]ަ‘,²whš¸ãe «re–ŸPÁ(++)“²i#s“t•Uh˜e“Hask˜ell“li•#st-ap˜p“en˜d‘ŸPo˜p“e «raÀtšÜror.‘ŸPUs“in˜g–ŸPa“BHA-stš¸ãyle“forw˜ard“a˜b-Ž¡‘,stract›¦µin±ÇtµUe «rpret•¸ãaÀt“ion‘[BHA85Ž‘ []˜requireGs˜buildinÜrg˜an˜inst“ance˜of˜Áfoldr˜²in˜t•Uh“e˜do-Ž¡‘,mÃŽain›=Ô[»4–J•¸!“»4“¸!“»4²]“¸!“»4“¸!“»6“¸!“»4².˜Thi#s˜giv•¸ãeGs˜an˜arguÜrm“en±Çt˜laÀtŸÿt“iñÆce˜of˜almoqstŽ¡‘,600,000–Ø1pGoinš±Çtàs.“CompuÜrt•¸ãaÀt“ion–Ø1of“t•Uh¸ãe“en˜tš¸ãire“fuÜrnct˜ion“graph“t˜ak˜eGs“on“t•Uh˜e“ordÕTe «rŽ¡‘,of–•Gan“hÃŽour“us#inÜrg“t•Uhš¸ãe“f*«ron±Çt˜ie «rs“algor*«it•Uhm‘[FH93Ž‘!],“wh˜e «reqas“wit•Uh“CDSs“compu•Ürt˜in“gŽ¡‘,just–œ#t•UhÃŽoqs1Çe“partàs“n¸ãee•GdšÕTe“d–œ#tÜro“d˜etµUe «rminš¸ãe“t•Uh˜e“en±Çt˜ire“ xpGoin±Çt“of“Áconcat“²t˜ak˜eGs“t˜w˜o“orŽ¡‘,t•Uhree–¬ s1Çeconš¸ãds“uÜrn˜dÕTe «r“s#imilar“circuÜrmst˜anceGs.“F‘ÿ*ªor“more“compãŽlex“fuÜrnct˜ion“spaceGs“t•Uh˜eŽ¡‘,di eš «rence–UUi#s“ev¸ãen“greqaÀtµUe˜r.Ž¡‘;Giv•¸ãen›"su“c“h˜an˜o“v“e «rwh“elminÜrg˜p#e «rformÃŽance˜adv‘ÿqÇan±Çt“age,˜it˜i#s˜tµUempt“in•Ürg˜t“o˜for-Ž¡‘,get–en±Çtš¸ãirely“a˜bGouÜrt“an˜y“ot•Uh˜e «r“ xpGoin±Çt˜inÜrg“sõTc˜h˜em˜e.“Y‘ÿ*ªet“in±ÇtµUegraÀt˜ion“of“CDS‘qbas1ÇeGdŽ¡‘, xpšGoin±Çt•¸ãinÜrg‘.+pro“v“e˜s‘.+trou•UbãŽle˜som“e›.+wh“en˜view“eGd˜f•*«rom˜a˜widÕTe «r˜f“ram•¸ãew“oràk.˜Th“e «re˜areŽ¡‘,t•¸ãw“o›ˆÚas-y“et˜uÜrnrešGsoãŽlv“e˜d–ˆÚi#sqsue˜s.“Fir•s“t•Uly‘ÿ*ª,–ˆÚas“di#sõTcusqs1Çe˜d“b#eloš¸ãw,“w˜e“h˜a˜v˜e“a“dšÕTeep“d˜eGs#ireŽ¡‘,tÜro›ÞQa•¸ãv“oid˜monomorphiñÆc˜anÃŽalys1ÇeGs˜of˜an“y˜kin“d.˜CDSs˜as˜pre•Gs1Çen±ÇtµUe“d˜so˜f#ar˜are˜purelyŽ¡‘,monomorphiñÆc.–;¯BecaŸÿus1Çe“of“t•Uhš¸ãe“n˜eešGd“tÜro“cloqs1Çely“exp˜oqs1Çe“d•ÕTep#en¸ãd“encie˜s›;¯b#et•¸ãw“een˜su•Ub-Ž¡‘,partàs–©¿of“t•Uhš¸ãe“inpuÜrt“an˜d“suš•Ub-partàs“of“t˜hš¸ãe“ou•Ürtʪpu“t,–©¿it“i#s“not“cleqar“hÃŽo˜w“t•Uh˜ey“mÃŽay“b#eŽ¡‘,us1ÇešGd–ý,in“a“p˜oãŽlymorphiñÆc“w¸ãay›ÿ*ª.“F˜or“ r•s“t-ordÕTe «r‘ý,MFš¸ãG-s“t˜yle–ý, xpGoin±Çt˜inÜrg,“pGoãŽlymorph-Ž¡‘,i•#sm›Q¹i“s˜not˜a˜probãŽlem:˜K•¸ãu•Ubiak‘[KHL91Ž‘‡"]˜h“as˜impãŽlem“en±ÇtµUe•Gd˜a˜p“oãŽlymorphiñÆc˜pro‘Ž8ject¸ãionŽ¡‘,anÃŽalys1Çe «r–UUwit•Uh“MFš¸ãG“ xpGoin±Çt˜inÜrg“in“t•Uh˜e“Glasgo˜w“Hask˜ell“compile «r.Ž¡‘;A‘—Èmore–—øimm¸ãešGdiaÀtµUe“probãŽlem“wit•Uh“lazy“ xp˜oin±Çtš¸ãinÜrg“i#s“hÃŽo˜w“tÜro“dÕTeqal“wit•Uh“mo•Gd˜ule“s.Ž¡‘,A‘dScrudÕTe›dWsõTc•¸ãh“em“e˜i#s˜tÜro˜expGort˜wh“aÀtµUev“e «r˜partàs˜of˜t•Uh“e˜a“bqstract˜fuÜrnct“ion˜graph˜h“a“v“eŽ¡‘,b#een–{SaggregaÀtµUeGd“whilst“compilinšÜrg“t•Uh¸ãe“dÕTe nin˜g“moGd¸ãule.“If,“compilin˜g“somš¸ãe“ot•Uh˜e «rŽ¡‘,moGd•¸ãule,›êt•Uh“e˜compile «r˜n“eeGds˜tÜro˜kno“w˜t•Uh“e˜ xpGoin±Çt˜aÀt˜som“e˜pGoin±Çt˜for˜whiñÆc“h˜noŽ¡‘,informÃŽaÀtš¸ãion–Òi#s“a˜v‘ÿqÇaila˜bãŽle,“it“i#s“som˜et˜im˜ešGs“p˜o•qs“s#ibãŽle–ÒtÜro“mÃŽak¸ãe“a“safe“e˜st¸ãimÃŽaÀtµUe“us#inÜrgŽ¡‘,monotÜroniñÆcit•¸ãy›UUan“d˜t•Uh“e˜informÃŽaÀt“ion˜whiñÆc“h˜Äis˜²a“v‘ÿqÇaila“bãŽle.Ž¡‘;F‘ÿ*ªor–ò!exampãŽle,“h•¸ãa“vinÜrg›ò!exp•GortµUe“d˜µG–Ìj²=“¸f²(µxŸÿ±1Ž–|sµ;›ª¨f‘ßùxŸÿ±1Ž“²)µ;˜²(µxŸÿ±2Ž“µ;˜f‘ßùxŸÿ±2Ž“²)¸g–ò!²w¸ãe“mÃŽay“wi#sh“tÜroŽ¡‘,knoš¸ãw–˜`(µf‘õ xŸÿ±3Ž‘|s²)“in“t•Uh˜e“cas1Çe“wh˜e «re“µxŸÿ±3Ž‘ ]ð¸v‘á}µxŸÿ±1Ž‘ Ó²an˜d“µxŸÿ±3Ž‘ ]ð¸v‘á}µxŸÿ±2Ž‘|s².“Since“µf‘«ï²i#s“monotÜroniñÆcŽ¡‘,it–GGfoãŽlloš¸ãws“t•Uh˜aÀt“µf–mâxŸÿ±3ޑ֯¸v‘ZSµf“xŸÿ±1Ž‘ú²an˜d›GGµf“xŸÿ±3ޑ֯¸v‘ZSµf“xŸÿ±2Ž‘|s²,˜an¸ãd˜so˜µf“xŸÿ±3ޑ֯¸v‘ZS²(µf“xŸÿ±1Ž‘Vž¸u‘Ú+µf“xŸÿ±2Ž‘|s²).Ž¡‘,Pro•¸ãvidÕTeGd›/õw“e˜are˜w“oràkinÜrg˜in˜a˜f*«ram“ew“oràk˜wh“e «re˜o“v“e «reGst“imÃŽaÀt“ion˜i•#s˜safe,˜t•Uhi“s˜giv¸ãeGsŽ¡‘,an›UUap•¸ãpro“ximÃŽaÀtµUe˜v‘ÿqÇalue˜for˜µf‘Ú§xŸÿ±3Ž‘|s².ŽŽŽŒ‹V gÌ\ ý¯3¤ 2Ì\ ýäÜš‘a²Cleqarly‘ÿ*ª,–üítš•Uh¸ãe“bigge «r“t˜h¸ãe“exp•GortµUe“d–üíµG²,“t˜h¸ãe“b#etŸÿtµUe «r“t˜hš¸ãe“e•Gst˜imÃŽaÀtµUe“s–üít•Uh˜aÀt“can“b#e“mÃŽadÕTeޤ ‘Rf*«rom–ÔTit.“BuÜrt“t•Uhš¸ãe“whÃŽoãŽle“purpGoqs1Çe“of“MF˜Gs“i#s“tÜro“k˜eep“µG“²as“smÃŽall“as“pGo•qs“s#ibãŽle,Ž¡‘Rcon±Çt•¸ãaininÜrg›ûp#e «rh“apqs˜a˜h“an“dful˜of˜pGoin±Çtàs˜ouÜrt˜of˜t•UhÃŽousan“ds˜of˜can“didÜraÀtµUeGs.˜Thi#sŽ¡‘Rmilit¸ãaÀtµUešGs–3Oagainst“mÃŽakinÜrg“go˜o˜d“ap•¸ãpro“ximÃŽaÀt“ions.–3OW‘ÿ*ªors1Çe,“not“all“t•Uh¸ãe“p˜oin±Çtàs“in“µGŽ¡‘R²mšÃŽay–•b#e“us1ÇeGd“in“m˜akinÜrg“t•Uhš¸ãe“ap˜pro˜ximÃŽaÀt˜ion:“in“t•Uh˜e“exampãŽle“a˜bGo˜v˜e,“w˜e“are“limitµUeGdŽ¡‘Rt•Üro›UUus#in“g˜pGoin±Çtàs˜¸f²(µy•[Ù;‘ª¨f‘Ú§y“²)–Ǹ2“µG–Ž0¸j“µxŸÿ±3Ž‘C‹¸v‘ǵy[Ù¸g².Ž¡‘aA‘>ås1Çeconš¸ãd,–?!equally“u•Ürn˜eGdifyin“g‘?!soãŽlu“t˜ion–?!i#s“tšÜro“expGort“not“only“µG²,“bu˜t“t•Uh¸ãe“re-Ž¡‘Rcurs#ivš¸ãe–ïGdomÃŽain“equaÀt˜ion“f*«rom“wh˜ence“it“cam˜e“{“or“ev˜en“t•Uh˜e“source“tµUext“whiñÆc˜hŽ¡‘Rb#egašÀt–dt•Uh¸ãe“equa˜tš¸ãion.“Th˜en,“wh˜en“µG“²cannot“answ˜eš «r“a“que˜ry‘ÿ*ª,“it“i#s“extµUenš¸ãdÕTeGd,“in“t•Uh˜eŽ¡‘RmÃŽann¸ãe «r›:ùdÕTe•GsõTcr*«ib#e“d˜aš¸ãb“o˜v˜e,–:ùas“requireGd.“If“t•Uh˜e“a˜bqstract“in±ÇtµUe «rpret˜aÀt˜ions“get“large,Ž¡‘Rdš¸ãu•Ürmpin“g–®/t•Uh˜em“inš±ÇtÜro“in˜tµUe «rfš#ace“ leGs“mÃŽay“not“b˜e“pract¸ãiñÆcal.“Thi˜s“sõTc•¸ãh“em“e–®/also“h¸ãas“aŽ¡‘Rmore›‘xsu••Ubt“le˜w•¸ãešqakn“eGs˜s.›‘xA‘‘hcru“cial˜ins#igh“t˜i#s˜t•Uh“aÀt˜ n“dinÜrg˜t•Uh“e˜ xpGoin±Çt˜of˜a˜domÃŽainŽ¡‘RequaÀt•¸ãion›¬ÐmÃŽak“eGs˜it˜st“an“d˜on˜itàs˜o“wn:˜it˜no˜lonÜrge• «r˜refe“renceGs˜an•¸ãy˜ot•Uh“e «r˜equaÀt“ion.Ž¡‘RCons#idÕTe «r–Í—t•Uhš¸ãe“foãŽllo˜winÜrg“t•Uhree“mo•Gd˜ule“s–Í—dÕTe ninÜrg“recurs#iv˜e“fuÜrnct˜ions“Áf²,“Ág“²an˜d“Áh“²wit•UhŽ¡‘Rcorre•Gsp“on•¸ãdinÜrg›UUequaÀt“ions˜Áf#²,˜Ág#˜²an“d˜Áh#²:Ž©¤m‘a¿÷Ámodule–?ýF(f)“where“{‘D?Ùf“=“...“f“...‘$¿ë}Ž¡‘a¿÷module–?ýG(g)“where“{“import“F;‘¿÷g“=“...“g“...“f“...“}Ž¡‘a¿÷module–?ýH(h)“where“{“import“G;‘¿÷h“=“...“h“...“g“...“}ަ‘R²Du•Ürmpin“g–UUt•Uhš¸ãe“uÜrnsoãŽlv˜eGd“domÃŽain“equaÀt˜ions“inš±ÇtÜro“in˜tµUe «rf#ace“(Á.hi²)“ lešGs“giv¸ãe˜s:ަ‘a¿÷ÁF.hi:‘¿÷f#–?ý=“...“f#“...Ž¡‘a¿÷G.hi:‘¿÷g#–?ý=“...“g#“...“f#“...Ž¡‘a¿÷H.hi:‘¿÷h#–?ý=“...“h#“...“g#“...ަ‘R²Wh•¸ãen›óªmoGd“ule˜ÁH‘ó²i•#s˜compileGd˜it˜mÃŽay˜b“e˜n•¸ãeceGsqsary˜tÜro˜extµUen“d˜t•Uh“e˜fuÜrnct“ion˜graphŽ¡‘Rfor–NôÁg#².“Th¸ãe“trouš•UbãŽle“i#s“t˜hi#s“m¸ãešqans“re˜adinÜrg“in±ÇtµUe «rf#ace“ÁF.hi“²ev¸ãen“tš•UhÃŽough“t˜h¸ãe“tµUext“ofŽ¡‘Rmo•Gd¸ãule›¹úÁH‘¹Ó²do#e“s˜not˜direct•Uly˜refe• «r˜tÜro˜ÁF²:˜in˜gen¸ãe“ral,˜it˜migh•¸ãt˜b#e˜n“eceGs•qsary˜tÜro˜re“ad˜allŽ¡‘Rin±ÇtµUe «rf#aceGs–Øin“t•Uhš¸ãe“do˜wn˜w˜ard“cloqsure“of“ÁH².“An˜y“sõTc˜h˜em˜e“whiñÆc˜h“expGortàs“inš±ÇtÜro“in˜tµUe «rf#aceŽ¡‘R le•Gs›Õœrefe «rence“s˜t•Üro˜fu“nct•¸ãions˜in˜ot•Uh“e «r˜mošGd“ule˜s–Õœsu e «rs“t•Uhš¸ãe“sam˜e“probãŽlem.“MÜre «relyŽ¡‘RinlininšÜrg–?]refe «renceGs“t˜o“ot•Uhš¸ãe «r“equaÀt˜ions“do#eGs“not“h˜elp,“as“t•Uhi#s“mÃŽak˜eGs“t•Uh˜e“in±ÇtµUe «rf#aceGsŽ¡‘Rcon±Çt•¸ãain›UUev“e «ryt•UhinÜrg˜b#elo“w˜t•Uh“em˜in˜t•Uh“e˜hie «rarc“h“y‘ÿ*ª,˜an“d˜h“ence˜v“e «ry˜large:ަ‘a¿÷ÁF.hi:‘¿÷f#–?ý=“...“f#“...Ž¡¡‘a¿÷G.hi:‘¿÷g#–?ý=“letrec“f#“=“...“f#“...‘/?åin“...“g#“...“f#“...Ž¡¡‘a¿÷H.hi:‘¿÷h#–?ý=“letrec“f#“=“...“f#“...‘/?åinŽ¡’¥ÿÐletrec–?ýg#“=“...“g#“...“f#“...‘ úin“...“g#“...“h#“...ަ‘R²BecaŸÿusš1Çe–ÃÊof“t•Uh¸ãeGs˜e“diculÜrt¸ãiešGs,“lazy“ xp˜oin±Çt¸ãinÜrg“do#e˜s“not“s1Çeem“tÜro“ t“w¸ãell“in“anŽ¡‘Ren•¸ãvironm“en±Çt›UUwh“e «re˜s1Çepara•ÀtµUe˜compila“t•¸ãion˜i#s˜t•Uh“e˜norm.ŽŸ¤m‘R»2.3‘ üP®9oßJlymorphišï¥c–ÕTor“Monomorphi˜c?ަ‘R²P•¸ãaram“etr*«iñÆc–~VpGoãŽlymorphiš#sm“i˜s“an“impGortš¸ãan±Çt“elem˜en±Çt“of“t•Uh˜e“t˜ypš#e“systµUems“of“moGdÕTe «r˜nŽ¡‘Rfu•Ürnct¸ãionÃŽal›UUlan“guageGs.˜Giv•¸ãen˜a˜param“etr*«i•ñÆcally˜pGoãŽlymorphi“c˜fuÜrnct•¸ãion,˜w“e˜could:ŽŽŽŒ‹kJ gÌ\ ý¯3¤ 2Ì\ ýäÜš‘2@»{ŽŽŽ‘=²ReGdo–ÂÝt•Uhš¸ãe“anÃŽalys•#i“s–ÂÝfor“eqac˜h“di e «ren±Çt“inst˜an±Çt˜iaÀt˜ion“of“t•Uh˜e“fuÜrnct˜ion.“Thiš#s“i˜sޤ ‘=equiv‘ÿqÇalen±Çt–ß—tšÜro“expan¸ãdin˜g“ou˜t“t•Uh¸ãe“program“in±Çt˜o“a“coãŽllect¸ãion“of“monomorphiñÆcŽ¡‘=inst¸ãanceGs–UUbš#efore“anÃŽalys˜i˜s.Ž© ÅÙ‘2@»{ŽŽŽ‘=²AnÃŽalys1Çe–&´t•Uhš¸ãe“fuÜrnct˜ion“once,“an˜d“us1Çe“pGoãŽlymorphiñÆc“in˜v‘ÿqÇar*«iance“reGsulšÜrtàs“t˜o“dÕTeqalŽ¡‘=wit••Uh›UUdi e «ren±Çt“ly˜inst•¸ãan±Çt“iaÀtµUe•Gd˜us1Çe“s˜laÀtµUe «r˜on.ŽŸQ‹‘,An–™æoft-quotµUeGd“di#sadv‘ÿqÇan±Çtš¸ãage“of“t•Uh˜e“form˜e «r“ap˜proac˜h“i#s“t•Uh˜aÀt“pGoãŽlymorphiñÆc“fuÜrnct˜ionsŽ¡‘,mšÃŽay–ãDb#e“an˜alys1ÇeGd“m˜anš¸ãy“t˜im˜eGs,“whiñÆc˜h“i#s“w˜astµUeful.“In“t•Uh˜e“w˜or•s“t–ãDcas1Çe,“t•Uh˜e“n•UuÜrm‘ÿ|qb#e «r“ofŽ¡‘,inst¸ãancešGs–àcan“b#e“exp˜on•¸ãen±Çt“ial–àin“tš•Uh¸ãe“lenÜrgt˜h“of“t˜hš¸ãe“program.“Nev˜e «rt•Uh˜eleGsqs,“su˜c˜h“b#e-Ž¡‘,h•¸ãa“viour–tfdoš#eGs“not“ap¸ãp˜eqar“tšÜro“oGccur.“M˜eqasuremš¸ãen±Çtàs“b˜y“Maràk“Jon˜eGs“of“s#ix“su•Ubqst˜an±Çt˜ialŽ¡‘,programs–6{in“t•Uhš¸ãe“Ánofib“²suitµUe‘[P˜ar92Ž‘qË]“suggeGst“a“t˜w˜ofoãŽld“increqas1Çe“in“t•Uh˜e“n•UuÜrm‘ÿ|qb#e «r“ofŽ¡‘,binš¸ãdinÜrg–¯groupqs‘[Jon93Ž‘±Ì].“F‘ÿ*ªurt•Uh˜e «r,“only“sš#impãŽle“li˜st-h•¸ãan“dlin•Ürg›¯fu“nct•¸ãions˜lik“e˜Ámap˜²an“dŽ¡‘,Áfoldr›S¨²h•¸ãa“v“e˜a˜large˜n•UuÜrm‘ÿ|qb#e «r˜of˜inst“anceGs,˜an“d˜su“c“h˜fuÜrnct“ions˜are˜oftµUen˜inlin“eGd˜b“yŽ¡‘,o•¸ãpt“imi•#s“inÜrg–°ícompile «rs“an•¸ãyw“ay‘ÿ*ª.–°íSo“monomorphiñÆc“anšÃŽalys•#i“s–°ím˜ay“not“actš¸ãually“in˜v˜oãŽlv˜eŽ¡‘,m•Uu•¸ãc“h›%d“upãŽliñÆcaÀt“ion˜of˜w“oràk.˜Obqs1Çe «rv“e˜also˜t•Uh“aÀt˜s#ince˜t•Uh“e˜a“bqstract˜in±ÇtµUe «rpret“aÀt“ions˜ofŽ¡‘,t¸ãyp#eGs–×õoftµUen“mšÃŽapqs“m˜anš¸ãy“t˜yp#eGs“tÜro“t•Uh˜e“sam˜e“laÀtŸÿt˜iñÆce,“monomorphi#saÀt˜ion“on“t•Uh˜e“bas•#i“sŽ¡‘,of–UUlaÀtšŸÿt¸ãiñÆceGs“ca˜us1ÇešGs“ev¸ãen“le˜sqs“expans#ion.ަ‘;More–qs1Çeš «r*«ious“i#s,“once“again,“t•Uh¸ãe“in±ÇtµUe˜ractš¸ãion“of“monomorphi#saÀt˜ion“wit•Uh“moGd-Ž¡‘,ulešGs.–^RF‘ÿ*ªor“a“mo˜d¸ãule“ÁM‘^O²exp˜ort¸ãinÜrg“a“p˜oãŽlymorphiñÆc“fuÜrnctš¸ãion“Áf²,“w˜e“can“eGit•Uh˜e «r“anÃŽalys1ÇeŽ¡‘,Áf–îɲaÀt“all“t•Uhš¸ãe“inst˜ancešGs“it“will“get“us1Çe˜d“aÀt,“or“wš¸ãe“can“w˜ait“uÜrn±Çt˜il“all“mo•Gd˜ule“s‘îÉa˜b“o˜v˜e‘îÉÁMŽ¡‘,²are–¼³compileGd“anš¸ãd“reqanÃŽalys1Çe“Áf“²on“an“as-n˜ee•GdÕTe“d›¼³bas•#i“s.˜Bot•Uh˜sõTc•¸ãh“em“eGs˜are˜uÜrnÃŽaÀtŸÿtract-Ž¡‘,iv•¸ãe,›æÏt•Uh“e˜ r•s“t˜b#ecaŸÿus1Çe˜it˜requireGs˜a˜do•¸ãwn“w“ard˜(ÁMain˜²tÜro˜ÁPrelude²)˜pasqs˜t••Uhrough˜t“h¸ãeŽ¡‘,mošGd¸ãule–ìggraph“tÜro“e˜sšt•¸ãa“bãŽli#sh‘ìgins˜t“an±Çt“iaÀt“ions,›ìgt•Uh“e˜s1Çecon“d˜b#ecaŸÿus1Çe˜of˜t•Uh“e˜n“eeGd˜tÜro˜carryŽ¡‘,arouÜrnš¸ãd–UUÁf²'s“source“tµUext“wh˜en“compilinÜrg“mo•Gd˜ule“s‘UUa˜b“o˜v˜e‘UUÁM².ަ‘;P¸ãoãŽlymorphiñÆc›\ÓanÃŽalys•#i“s˜circuÜrm•¸ãv“en±Çtàs˜bGot•Uh˜probãŽlems˜b•#ecaŸÿus1Çe˜a˜s“inÜrgle˜anÃŽalys“i“sŽ¡‘,s1Çeš «rv¸ãeGs–È[all“que˜rš*«ieGs,“ev¸ãen“t•UhÃŽoqs1Çe“f˜rom“di e «ren±Çt“mo•Gdš¸ãule“s.–È[W‘ÿ*ªoràk“b˜y“Baraki,“Hugh˜eGsŽ¡‘,an•¸ãd›mLaŸÿuÜrnc“h“bury‘[Bar93Ž‘,˜HL92bŽ‘!»X]˜(tÜro˜m“en±Çt“ion˜buÜrt˜a˜few)˜h“as˜ešGst“a“bãŽli#sh“e˜d‘mtµUec“h-Ž¡‘,niquešGs–0#for“b˜ot•Uh“forwš¸ãard“an˜d“bac˜kw˜ard“pGoãŽlymorphišñÆc“str*«i˜ctn¸ãešGsqs“anÃŽalys1Çe˜s.“Bac¸ãk-Ž¡‘,wš¸ãard–¯%anÃŽalys1ÇeGs“len˜d“t•Uh˜ems1Çelv˜eGs“part˜iñÆcularly“w˜ell“tÜro“su˜c˜h“an“ap˜proac˜h:“Sect˜ion“5Ž¡‘,of‘[Sew94Ž‘8ç]›ËdÕTe•GsõTcr*«ib#e“s˜su•¸ãc“h˜an˜anÃŽalys•#i“s˜in˜cons“id•ÕTe «ra¸ãbãŽle˜d“et•¸ãail.˜Baraki's˜w“oràk˜in“diñÆc-Ž¡‘,aÀtµUeGs–ÕþhÃŽoš¸ãw“som˜e“forw˜ard“anšÃŽalys1ÇeGs“m˜ay“b#e“m˜adÕTe“pGoãŽlymorphiñÆc:‘[Sew94Ž‘8ç],“Sect¸ãion“3Ž¡‘,dÕTe•GsõTcr*«ib#e“s–UUan“impãŽlem•¸ãen±Çt“aÀt“ion.ަ‘;F‘ÿ*ªor›œd r•s“t˜ordÕTe «r˜fuÜrnct•¸ãions,˜pGoãŽlymorphiñÆc˜tµUec“hniqueGs˜giv“e˜t•Uh“e˜sam“e˜reGsulÜrtàs˜asŽ¡‘,monomorphiñÆc›82anÃŽalys•#i“s:˜t••Uh¸ãey˜are˜exact.˜BuÜrt˜in˜t“h•¸ãe˜high“e• «r˜ordÕTe“r˜cas1Çe,˜accuracyŽ¡‘,mšÃŽay–äÍb#e“loqst.“F‘ÿ*ªor“bac•¸ãkw“ard–äÍan˜alys1ÇeGs,“whiñÆcš¸ãh“are“inh˜eš «ren±Çt•Uly“ r•s“t-ordÕTe˜r,–äÍt•Uhi#s“mÃŽayŽ¡‘,b#e›Çaccept•¸ãa“bãŽle.˜F‘ÿ*ªor˜ot•Uh“e «r˜anÃŽalys1ÇeGs,˜t•Uh“e˜mÃŽagnit“udÕTe˜of˜t•Uhi#s˜probãŽlem˜h“as˜y“et˜tÜro˜b#eŽ¡‘,quan±Çt¸ãi eGd.ŽŸ!Ý<‘,»2.4‘ üHigh®9eš Dr–ÕTor“ r•-s“t‘ÕTordÎîe˜r?ŽŸÝ<‘,²High¸ãe• «r›½ ordÕTe“r˜ xpGoin±Çt¸ãin•Ürg˜i#s˜dicul“t˜b#eca•Ÿÿus1Çe˜t•Uh¸ãe˜laÀt“t•¸ãiñÆce˜s#izeGs˜for˜fuÜrnct“ion˜spaceGsŽ¡‘,gro¸ãw–8ãso“rapidly›ÿ*ª.“F˜or“exampãŽle,“in“str*«iñÆctnš¸ãeGsqs“anÃŽalys•#i“s,–8ãan“itµUem“of“t˜yp#e“Á[Int]–?ý->“[Int]Ž¡‘,²migh•¸ãt›†±a“bqstract˜tÜro˜domÃŽain˜[»4–\¸!“»4²],˜whiñÆc•¸ãh˜h“as˜35˜pGoin±Çtàs.˜AddinÜrg˜a˜s1Çecon“d˜para-Ž¡‘,mš¸ãetµUe «r–o«of“t•Uh˜e“sam˜e“t˜yp#e“giv˜ešGs“domÃŽain“[»4–Ǹ!“»4“¸!“»4²],–o«wit•Uh“24,696“p˜oin±Çtàs,“an“increqas1ÇeŽ¡‘,of›¾Úo•¸ãv“e «r˜700˜t“im“eGs.˜Th“e˜n•UuÜrm‘ÿ|qb#e «r˜of˜pGoin±Çtàs˜in˜[»4–võ¸!“»4“¸!“»4“¸!“»4²]˜i#s˜ce «rt•¸ãainly˜v“e «ryŽŽŽŒ‹|  gÌ\ ý¯3¤ 2Ì\ ýäÜš‘R²large.–ÂoManš¸ãy“fuÜrnct˜ionÃŽal“param˜etµUe «rs“h˜a˜v˜e“t˜yp#ešGs“more“compãŽliñÆcaÀtµUe˜d“tš•Uh¸ãan“t˜hi#s,“an¸ãdޤ ‘RcalculaÀtš¸ãinÜrg–UUcompãŽletµUe“ xpGoin±Çtàs“in“t•Uh˜ešGir“pre˜s1Çence“i#s“impract¸ãiñÆcal.Ž¡‘aFixpGoin±Çt•¸ãinÜrg›øÖb“y˜tµUe «rm˜rewr*«it“inÜrg˜som“et“im“eGs˜f#ails˜in˜t•Uh“e˜preGs1Çence˜of˜fuÜrnct“ionÃŽalŽ¡‘Rparamš¸ãetµUe «rs.–¥ In“t•Uh˜e“gen˜e «ral“cas1Çe,“high˜eš «r“ordÕTe˜r“equaÀtš¸ãions“cannot“b#e“soãŽlv˜eGd,“b#ecaŸÿus1ÇeŽ¡‘Rt•Uh¸ãe•Gir›æ xp“oin±Çtàs˜dÕTep#en•¸ãd˜on˜t•Uh“e˜ xpGoin±Çtàs˜of˜t•Uh“e˜fuÜrnct“ionÃŽal˜param“etµUe «rs.˜Th“e˜usualŽ¡‘Rmš¸ãet•UhÃŽoGd–Õ›of“rewr*«it˜inÜrg“adjacen±Çt“ap˜pro˜ximÃŽaÀt˜ions“tšÜro“normÃŽal“form“f#ails“t˜o“dÕTetµUect“anŽ¡‘Ro•¸ãv“e «rall–` xpGoin±Çt“b#ecaŸÿusš1Çe“su•Ubqs˜equenš±Çt“ap•¸ãpro“ximÃŽaÀt“ions‘`con˜t“ain›`som“e˜tµUe «rm˜in“v“oãŽlvinÜrgŽ¡‘Ra–töfuÜrnctš¸ãionÃŽal“param˜etµUe «r“ap˜pãŽlieGd“more“an˜d“more“t˜im˜ešGs.“Thi#s“o˜ccurs,“for“exampãŽle,Ž¡‘Rin–UU xpGoin±Çtš¸ãinÜrg“forw˜ards“a˜bqstract˜ions“of“Áfoldr²:Ž©HÙ‘a¿÷Áfoldr#(n)›¿÷=–?ý\f“a“xs“->“...“f“(f‘ÿô...“(f“E)“...˜)“...Ž¡¡‘a¿÷foldr#(n+1)–?ý=“\f“a“xs“->“...“f“(f“(f“...“(f“E)“...“)“)“...ަ‘R²whš¸ãe «re–ÁE‘ë²i#s“som˜e“arbitrary“tµUe «rm,“an˜d“Áfoldr#(n)“²an˜d“Áfoldr#(n+1)“²dÕTenotµUe“t˜w˜oŽ¡‘Radjacen±Çt›1ºap•¸ãpro“ximÃŽaÀt“ions˜tÜro˜t•Uh“e˜ xpGoin±Çt.˜He «re,˜Áf˜²i#s˜a˜fuÜrnct“ionÃŽal˜param“etµUe «r˜b#eGinÜrgŽ¡‘Rwrapš¸ãp#eGd–£‚more“an˜d“more“t˜im˜eGs“arouÜrn˜d“ÁE²,“t•Uh˜e «reÕTb˜y“mÃŽakinÜrg“syn±Çt˜act˜iñÆc“dÕTetµUect˜ion“ofŽ¡‘Ra–Åú xpšGoin±Çt“imp˜o•qs“s#ibãŽle.–ÅúOf“cours1Çe,“if“t•Uh¸ãe“tšµUe «rm“rewr*«it˜e «r“i#s“extremš¸ãely“clev˜e «r“it“canŽ¡‘RdÕTetµUect–¦#t•Uhš¸ãaÀt,“for“som˜e“suit˜a˜bšãŽly“large“µn²,“ÁfŽ‘æ Ÿü\p´nŽ‘¥b²=‘MÄÄ xŽ‘¡ÁfŽ‘Rž²,“so“it“can“rep˜lace“ÁfŽ‘ 3ä²(Ä xŽ‘ÄÝÁfŽ‘Ú²)“b¸ãyŽ¡‘RÄ xŽ‘`>1ÁfŽ‘h«à²an•¸ãd›-²t•Uh“e «reÕTb“y˜gen“e «raÀtµUe˜normÃŽal˜forms˜whiñÆc“h˜dÕTep#en“d˜expãŽliñÆcit•Uly˜on˜Áf²'s˜ xpGoin±Çt.Ž¡‘RTh¸ãe–‘prequireGd“pašÀtŸÿtµUe «r#n“mÃŽa˜t•¸ãc“hinÜrg–‘piš#s“tr*«iñÆc¸ãky“{“not“so“s˜impšãŽle“for“dou•Ub˜ly“recurs#iv¸ãeŽ¡‘RtµUe «rms–Ø_{“anš¸ãd“w˜e“n˜eeGd“tÜro“d•ÕTecid“e–Ø_on“a“suit˜a˜bãŽle“µn².“Th˜e“v‘ÿqÇalue“of“µn“²dÕTep#en˜ds“on“t•Uh˜eŽ¡‘RfuÜrnctš¸ãion–Ü­space“in“queGst˜ion“{“cleqarly‘ÿ*ª,“w˜e“n˜eeGd“a“quiñÆc˜k“algor*«it•Uhm“for“givinÜrg“aŽ¡‘Rgo•Go“d›‚‰o•¸ãv“e «reGst“imÃŽaÀtµUe˜of˜t•Uh“e˜fuÜrnct“ion˜space's˜h“eGigh“t.˜Nielson˜an“d˜Nielson˜lošGok“e˜d‘‚‰aÀtŽ¡‘Rtš•Uhi#s–žüprobãŽlem‘[NN92Ž‘],“buÜrt“t˜hš¸ãeGir“w˜oràk“can“giv˜e“exceGsqs#iv˜ely“large“e•Gst˜imÃŽaÀtµUe“s–žüan˜d“i#sŽ¡‘Rof–Æ[limitµUeGd“ap•¸ãpãŽliñÆca“bilit“y‘ÿ*ª.–Æ[A‘Æ>more“fu•Ürnš¸ãd“am˜en±Çt˜al–Æ[probšãŽlem“i#s“pGo˜lymorphi#sm:“in“t•Uh¸ãaÀtŽ¡‘Rcas1Çe,–ã¾µn“²v‘ÿqÇar*«ieGs“witš•Uh“t˜hš¸ãe“inst˜an±Çt˜iaÀt˜ion,“so“t•Uh˜e“not˜ion“of“compu•Ürt˜in“g–ã¾a“s#inÜrgle“v‘ÿqÇalueŽ¡‘Rfor–UUit“i#s“nons•1Çens“e.Ž¡‘aNev•¸ãeš «rt•Uh“eleGsqs,–Æfor“high¸ãe˜r“ordÕTe˜r“equaÀtš¸ãions“whiñÆc˜h“do“not“dÕTep#en˜d“on“t•Uh˜e“ xpGoin±ÇtàsŽ¡‘Rof–˜1t•Uhš¸ãeGir“fuÜrnct˜ionÃŽal“param˜etšµUe «rs,“t˜e «rm“bas1ÇešGd“ xp˜oin±Çtš¸ãinÜrg“w˜oràks“w˜ell“an˜d“can“b#eŽ¡‘Rt•UhÃŽousanš¸ãds–äof“t˜im˜eGs“c˜h˜eqap#e «r“t•Uh˜an“us#inÜrg“f*«ron±Çt˜ie «rs.“Su˜c˜h“equaÀt˜ions“can“b#e“gen˜e «raÀtµUeGd,Ž¡‘Rfor–ÕžexampãŽle,“f*«rom“t•Uhš¸ãe“forw˜ards“a˜bqstract˜ions“of“Ámap“²an˜d“Áfilter“²([Sew94Ž‘8ç],“Sect˜ionŽ¡‘R4.3.5).ŽŸHÙ‘R»In–ÄëdšÎîefence“of“ r•-s“t–Äëord˜e Dr“anº}alys•(äi“s‘²Thi•#s›%«pap“e• «r˜argueGs˜against˜high¸ãe“r˜ordÕTe“rŽ¡‘RanÃŽalys1ÇešGs.–^ÅWh¸ãen“mo˜d¸ãule˜s“are“also“t•¸ãak“en–^Åin±ÇtšÜro“accou˜n±Çt,“tš•Uh¸ãe“n˜uÜrm‘ÿ|qbš#e «r“of“dÕTeGs˜ign“con-Ž¡‘Rstrainš±Çtàs–ó§b#ecom¸ãeGs“in˜tÜro•ãŽle «raš¸ãb“le.–ó§Can“su˜c˜h“a“sštµUep“b#e“jus˜tš¸ãi eGd?“W‘ÿ*ªell,“t˜ak˜en“in“a“widÕTe «rŽ¡‘Rcon±ÇtµUext,–9:mÃŽayb#e.“High¸ãeš «r“ordÕTe˜r“fuÜrnct¸ãions“dÕTefeqaÀt“adv‘ÿqÇancešGd“co˜dÕTe“gen•¸ãe «raÀt“ion‘9:tµUec“h-Ž¡‘RniqueGs,–Zlikš¸ãe“ar*«it˜y“c˜h˜ec˜k“a˜v˜oidšÜrance,“u˜n‘ÿ|qbGo¸ãxin˜g“an¸ãd“argu˜m¸ãen±Çtàs“in“regiš#s•tµUe «r“s,‘Zs˜inceŽ¡‘Rt•Uh¸ãey–®™repreGs1Çen±Çt“calls“tšÜro“compãŽletµUely“u˜nkno¸ãwn“fu˜nct¸ãions.“A–ÿqÇugustàsqson‘[A“ug93Ž‘€]‘®™sug-Ž¡‘RgeGstàs–>—t•Uhš¸ãaÀt“callinÜrg“a“kno˜wn“fuÜrnct˜ion“coqstàs“h˜alf“as“m•Uu˜c˜h“as“callinšÜrg“an“u˜nkno¸ãwnŽ¡‘Ron¸ãe.Ž¡‘aTh•¸ãe›ô(Hask“ell)˜compile «r˜comm•UuÜrnit“y˜go˜tÜro˜cons#idÕTe «ra“b•ãŽle˜trou•Ub“le˜tÜro˜get˜r*«id˜ofŽ¡‘Rcalls–UUtÜro“high¸ãeš «r“ordÕTe˜r“fuÜrnct¸ãions.“F‘ÿ*ªor“exampãŽle:ަ‘X@»{ŽŽŽ‘c²SimpãŽle–›non-recuršs#iv¸ãe“com‘ÿ|qbinÃŽaÀtÜror˜s“likš¸ãe“Á(.)“²an˜d“ÁthenS‘šÑ²are“inlin˜eGd“(in“Glasgo˜wŽ¡‘cHask¸ãell).ŽŽŽŒ‹ ‘À gÌ\ ý¯3¤ 2Ì\ ýäÜš‘2@»{ŽŽŽ‘=²PreludÕTe–uDfuÜrnctš¸ãions“whiñÆc˜h“pasqs“fuÜrnct˜ionÃŽal“param˜etµUe «rs“alonšÜrg“u˜nc•¸ãh“an˜geGd,‘uDlik“eޤ ‘=Ámap–UU²an¸ãd“Áfoldr²,“are“ušÜrnfoãŽldÕTeGd“t˜o“form“sp•#eciali“s1ÇeGd›UUv¸ãe «rs“ions˜(in˜Y‘ÿ*ªale˜Hask¸ãell).Ž© E‘2@»{ŽŽŽ‘=²Ov•¸ãe «rloadÕTeGd›üefuÜrnct“ions˜are˜sp•#eciali“s1Çe•Gd˜aÀt˜t•Uh¸ãe“ir˜us1Çe˜inst¸ãance“s,˜aÀt˜leqast˜wit•UhinŽ¡‘=s#inÜrgle›ÚÈmo•Gd¸ãule“s˜(Glasgo•¸ãw˜an“d˜Ch“alm“e «rs).˜Thi#s˜a“v“oids˜a˜gre•qaÀt˜dÕTe“al˜of˜t•Uh¸ãeŽ¡‘=high¸ãe• «r›uGordÕTe“r˜mÃŽac•¸ãhin“e «ry˜whiñÆc“h˜i#s˜oft•µUen˜asqsošGciaÀt“e˜d–uGwit•Uh“impãŽlem•¸ãen±Çt“aÀt“ions‘uGofŽ¡‘=o•¸ãv“e «rloadinÜrg.ŽŸÏ‘,Nelan‘[Nel91Ž‘¸ç]›ìødÕTe•GsõTcr*«ib#e“s˜aÀt˜som•¸ãe˜lenÜrgt•Uh˜tµUec“hniqueGs˜for˜wh“aÀt˜h“e˜tµUe «rm“eGd˜Ä rsti c-Ž¡‘,ation²:–ælt•Uhš¸ãe“aŸÿu•Ürt“omÃŽaÀt˜iñÆc–ælremo˜v‘ÿqÇal“of“high˜eš «r“ordÕTe˜r“fušÜrnct¸ãions.“Al˜t•UhÃŽough“con•¸ãv“e «rs#ion‘ælofŽ¡‘,high¸ãe• «r-ordšÕTe“r–iprograms“tÜro“ r•s“t-ord˜eš «r–ii#s,“in“gen¸ãe˜ral,“impGo•qs“s#ibãŽle,–iprogramm¸ãe˜rs,“b¸ãyŽ¡‘,anš¸ãd–83large,“us1Çe“high˜e• «r-ordÕTe“r#n˜eGsqs–83in“ce «rt˜ain“idiomÃŽaÀt˜iñÆc“w˜ays“whiñÆc˜h“Äar‘ÿ}'e“²am˜enÃŽa˜bãŽle“tÜroŽ¡‘, r•s“t•¸ãi caÀt“ion–ýDusš#inÜrg“Nelan's“mÃŽac•¸ãhin“e «ry‘ÿ*ª.–ýDThi˜s“mÃŽac•¸ãhin“e «ry‘ÿ*ª,›ýDcom‘ÿ|qbin“e•Gd˜wit•Uh˜aggre“sqs#iv¸ãeŽ¡‘,inlininÜrg,–´‘can“b#e“remÃŽaràkñÆaš¸ãbãŽly“e ect˜iv˜e.“Ev˜en“wit•UhÃŽoušÜrt“us#in˜g“ r•s“t•¸ãi caÀt“ion,›´‘m•Uu“c“h˜ofŽ¡‘,t•Uh•¸ãe›UUo“pt“imi#s1Çe•Gd˜co“d•ÕTe˜d“eqalÜrt˜wit•Uh˜ins#id“e˜Glasgo•¸ãw˜Hask“ell˜i#s˜purely˜ r•s“t˜ordÕTe «r.ަ‘;F‘ÿ*ªrom–ÐAa“str*«iñÆctn¸ãešGsqs“anÃŽalys•#i“s–ÐAp˜oin±Çt“of“view,“ r•s“t–ÐAordÕTe «r“anÃŽalys•#i“s–ÐAhš¸ãas“t˜w˜o“mÃŽa‘Ž8jorŽ¡‘,adv‘ÿqÇan±Çt¸ãageGs:ŽŸ‘2@»{ŽŽŽ‘=²FixpGoin±Çt¸ãinÜrg–¸Ôiš#s“eqas˜ie «r.“Thš¸ãe“f*«ron±Çt˜ie «rs“algor*«it•Uhm“ruÜrns“reqasonÃŽa˜bãŽly“quiñÆc˜kly“forŽ¡‘= r•s“t–ñRordÕTe «r“exampãŽleGs‘([Sew94Ž‘8ç],“Sectš¸ãion“3),“an˜d“tšµUe «rm“rewr*«it˜e“bas1ÇešGd“ xp˜oin±Çt¸ãinÜrgŽ¡‘=i#s–îáguaran±ÇtµUeeGd“tšÜro“w¸ãoràk.“Compu˜t¸ãin˜g“compãŽletµUe“fu˜nct¸ãion“graphs“do#ešGs“not“lo˜okŽ¡‘=quitµUe–Êso“bad“in“t•Uhš¸ãe“ r•s“t–ÊordÕTe «r“cas1Çe,“an˜d“doinÜrg“so“mÃŽak˜ešGs“mo˜d¸ãule˜s“eqas#ie «r“tÜroŽ¡‘=dÕTeqal‘UUwit•Uh.ަ‘2@»{ŽŽŽ‘=²P•¸ãoãŽlymorphiñÆc›6Ègen“e «rali#saÀt“ion˜giv“e•Gs˜exact˜re“sulÜrtàs.˜MonomorphiñÆc˜anÃŽalys•#i“s˜an¸ãdŽ¡‘=itàs–UUaÀtŸÿtµUenš¸ãdÜran±Çt“mo•Gd˜ule-relaÀtµUe“d–UUprobãŽlems“can“b#e“a˜v˜oidÕTeGd“en±Çt˜irely‘ÿ*ª.ŽŸ%Š¿‘,Ó3‘ €Th• e›€Defr9™iv“e•`d˜De“s0ignŽŸ$Y‘,»3.1‘ üOv®9e DrviewŽŸ$Y‘,²Cons#idšÕTe «r*«inÜrg–Ÿ—t•Uh¸ãe“d˜ešGs#ign“constrain±Çtàs,“it“lo˜oks“lik¸ãe“a“ r•s“t-ordÕTe «r,–Ÿ—p˜oãŽlymorphiñÆc“anÃŽa-Ž¡‘,lys•#i“s›ïcompu•Ürt¸ãin“g˜compãŽletµUe˜ xe•Gd˜p“oin±Çtàs˜migh¸ãt˜form˜a˜p•ãŽlaŸÿus#ib“le˜bas•#i“s˜for˜a˜w¸ãoràkinÜrgŽ¡‘,systµUem,–çkso“t•Uhiš#s“i˜s“whš¸ãaÀt“h˜as“b#een“constru˜ctšµUeGd.“A‘ÿqÇbqstract“in±Çt˜e «rpret•¸ãaÀt“ion‘çkprošGd“u“ce˜sŽ¡‘,tµUe «rms–­âin“wh¸ãaÀt“can“bš#e“cons˜idÕTe «reGd“tÜro“b˜e“an“aš¸ãbqstract“lam‘ÿ|qbGdÜra-calculus,“an˜d“ xpGoin±Çt-Ž¡‘,inÜrg–õHi#s“don¸ãe“wit•Uh“a“t•µUe «rm-rewr*«it“e›õHsyst“em˜whiñÆc•¸ãh˜transforms˜s1ÇemÃŽan±Çt“iñÆcally˜equiv‘ÿqÇalen±ÇtŽ¡‘,tµUe «rms–UUtÜro“synš±Çt•¸ãact“iñÆcally‘UUidÕTen˜t“iñÆcal–UUnormÃŽal“forms.ަ‘;Thš¸ãe–XŒanÃŽalys1Çe «r“forms“part“of“t•Uh˜e“Glasgo˜w“Hask˜ell“compile «r,“an˜d“o˜p#e «raÀtµUeGs“on“aŽ¡‘,dÕTe•Gsugare“d–´£Hask¸ãell“form“lošGoqs1Çely“refe «rre˜d“tÜro“as“Core.“Core“allo¸ãws“lam‘ÿ|qb˜dÜra“tµUe «rms,Ž¡‘,ap•¸ãpãŽliñÆcaÀt“ions,–íalitµUe «rals,“loGcal“binš¸ãdinÜrgs,“on˜e-lev˜el“pašÀtŸÿtµUe «r#n“mÃŽa˜t•¸ãc“hinÜrg–ía(Ácase²s)“an¸ãd“con-Ž¡‘,stru•¸ãctÜror›¬Òap“pãŽliñÆcaÀt“ions.˜T“yp#e˜informÃŽaÀt“ion˜sup“pãŽlieGd˜b“y˜previous˜compile «r˜ph“as1ÇeGsŽ¡‘,m•¸ãeqans›ft•Uh“e˜t“yp#e˜(an“d˜h“ence˜t•Uh“e˜a“b•qstract˜domÃŽain)˜as“so•GciaÀtµUe“d˜wit••Uh˜ev¸ãe «ry˜su“b#ex-Ž¡‘,preGsqs•#ion›(\i“s˜kno•¸ãwn.˜Th“e˜Core˜tree˜i#s˜annot“aÀtµUeGd˜wit••Uh˜t“h•¸ãe˜str*«iñÆctn“eGsqs˜informÃŽaÀt“ionŽ¡‘,compu•ÜrtµUeGd,›Á^mÃŽakin“g˜it˜a•¸ãv‘ÿqÇaila“bãŽle˜tÜro˜su•Ubqs1Çequen±Çt˜transformÃŽaÀt“ion˜pasqs1ÇeGs,˜an“d˜tÜro˜t•Uh“eŽ¡‘,in•±ÇtµUeš «rf#ace-pr*«in“t•¸ãinÜrg‘bmÃŽac“hin“e˜ry‘ÿ*ª,–bso“ot•Uh¸ãe˜r“mo•Gdš¸ãule“s–bcan“kno˜w“a˜bGouÜrt“t•Uh˜e“str*«iñÆctn˜eGsqs“ofŽ¡‘,fuÜrnctš¸ãions–UUin“t•Uhi#s“on˜e.ŽŽŽŒ‹ ¦b gÌ\ ý¯3¤ 2Ì\ ýäÜš‘R»3.2‘ üTh•®9e›ÕTa“b µs-tract˜in¦ tª"e Drpret“a¶ft“ionŽŸ‘³‘R²A‘ÿqÇbqstract›’)in±ÇtµUe «rpret•¸ãaÀt“ions˜for˜str*«iñÆctn“eGsqs˜anÃŽalys•#i“s˜h•¸ãa“v“e˜hi•#stÜror*«iñÆcally˜b“een˜caÀtµUegor-ޤ ‘Ri#s1ÇeGd–Bas“forwš¸ãard“or“bac˜kw˜ard‘[Hug90Ž‘>],“alÜrtš•UhÃŽough“t˜hš¸ãe“ap˜p#eqarance“of“relaÀt˜ionšÃŽal“an˜a-Ž¡‘Rlys1ÇeGs–û˜i#s“noš¸ãw“bãŽlurr*«inÜrg“t•Uh˜aÀt“di#st˜inct˜ion.“Bac˜kw˜ard“anÃŽalys1ÇeGs“gen˜e «rašÀtµUe“informÃŽa˜t¸ãionŽ¡‘Raš¸ãbGou•Ürt‘Þáfu“nct˜ion‘Þáargu“m˜en±Çtàs–Þágiv˜en“kno˜wleGdge“of“som˜e“pro˜p#e «rt˜y“of“t•Uh˜e“ap˜pãŽliñÆcaÀt˜ionŽ¡‘Ras–Þ›a“whÃŽošãŽle.“F‘ÿ*ªor“examp˜le,“bac•¸ãkw“ard›Þ›str*«iñÆctn“eGsqs˜anÃŽalys•#i“s˜of˜an˜µn²-argu•Ürm¸ãen±Çt˜fu“nct¸ãionŽ¡‘RprošGd•¸ãu“ce˜s–H3µn“²mÃŽapšqs,“on¸ãe“for“e˜acš¸ãh“arguÜrm˜en±Çt,“mÃŽap˜pinÜrg“dÕTemÃŽan˜d“on“an“ap˜pãŽliñÆcaÀt˜ion“tÜroŽ¡‘RdÕTemÃŽanš¸ãd–ñ»on“eqac˜h“arguÜrm˜en±Çt.“As“tš•Uhi#s“impãŽlieGs,“t˜hš¸ãe“fu•Ürn˜d“am˜en±Çt˜al–ñ»a˜bqstract“en±Çt˜it˜ieGs“areŽ¡‘RpšGoin±Çtàs–˜in“laÀtŸÿt¸ãiñÆce˜s,“wh¸ãeš «re“di e˜renš±Çt“pGoin˜tàs“dÕTenotµUe“di e «ren˜t“dÕTemÃŽanš¸ãds“or“\n˜ee•GdÕTe“d-Ž¡‘Rnš¸ãeGsqs"–’for“som˜e“dÜraÀt˜a“stru˜ct˜ure.“It“i#s“usual“tÜro“(aÀt“leqast“pGotµUen±Çt˜ially)“allo˜w“eqac˜hŽ¡‘Rdi e «ren±Çt–*çconcretµUe“tš¸ãyp#e“tÜro“h˜a˜v˜e“itàs“o˜wn“laÀtŸÿt˜iñÆce“of“a˜bqstract“dÕTemÃŽan˜ds,“in“ordÕTe «r“t•Uh˜aÀtŽ¡‘Rwš¸ãe–UUcan“do“dÕTet˜ailešGd“anÃŽalys1Çe˜s“wit•Uh“dÜraÀtš¸ãa“stru˜ct˜ureGs.Ž© PW‘aAlÜrt••UhÃŽough›­Ût“h¸ãe˜ r•s“t˜s“tr*«iñÆctn¸ãe•Gsqs˜anÃŽalys1Çe“s˜w•¸ãe «re˜of˜t•Uh“e˜forw“ards˜t“yp#e,˜laÀtµUe «r˜dÕTe-Ž¡‘Rv•¸ãelo“pm“en±Çt›{Tsugge•GstµUe“d˜bac•¸ãkw“ards˜anÃŽalys•#i“s˜migh¸ãt˜b“e˜quiñÆc•¸ãk“e «r˜an“d˜giv“e˜a˜s#impãŽle «rŽ¡‘RtreqaÀt•¸ãm“en±Çt–$7of“pGoãŽlymorphi#sm,“anš¸ãd“pract˜iñÆcal“w˜oràk“s1Çeems“tÜro“bš#eqar“t•Uhi˜s“ouÜrt‘([Sew94Ž‘8ç],Ž¡‘RSectš¸ãion–íâ5).“Th˜e“few“pap#e «rs“shÃŽo˜winÜrg“hÃŽo˜w“str*«iñÆctn˜eGsqs“informÃŽaÀt˜ion“can“b#e“us1ÇeGd“tÜroŽ¡‘Rgen¸ãeš «raÀt•µUe‘c&b#etŸÿt“e˜r–c&cošGdÕTe‘[PJ93Ž‘ñË,“Hal93Ž‘ªG]“all“e˜it•Uh¸ãe «r“sugge˜st“or“impãŽly“t•Uhš¸ãaÀt“bac˜kw˜ardsŽ¡‘RinformÃŽaÀtš¸ãion–F.i#s“wh˜aÀt“i#s“act˜ually“us1Çeful.“T‘ÿ*ªak˜en“tÜroget•Uh˜e «r,“t•Uh˜e“cas1Çe“for“buildinÜrg“aŽ¡‘Rbac•¸ãkw“ards›UUa“bqstract˜in±ÇtµUe «rpret“aÀt“ion˜s1Çeems˜o“v“e «rwh“elminÜrg.ަ‘aSpace›äblimit•¸ãaÀt“ions˜precludÕTe˜m•Uu“c“h˜di•#sõTcusqs“ion˜of˜t•Uh•¸ãe˜a“bqstract˜in±ÇtµUe «rpret“aÀt“ion.Ž¡‘RSuce–¾±it“tÜro“say“t•Uh¸ãaÀt“it“iš#s“f˜airly“con•¸ãv“en±Çt“ionÃŽal:›¾±t•Uh“e˜o“v“e «rall˜stru“ct“ure˜i•#s˜s“imilar˜tÜroŽ¡‘Rt•Uh¸ãaÀt›—pre•Gs1Çen±ÇtµUe“d˜b•¸ãy˜John˜Hugh“eGs˜in‘[Hug90Ž‘>],˜alÜrt••UhÃŽough˜t“h•¸ãe˜m“ec“h“ani#sm˜for˜dÕTeqalinÜrgŽ¡‘Rwit•Uh–¸ØdÜraÀtš¸ãa“stru˜ct˜ureGs,“cons•tru˜ctÜror“s–¸Øan˜d“cas1Çe“tµUeš «rms“i#s“di e˜ren±Çt.“As“wit•Uh“an¸ãy“purelyŽ¡‘Rbac•¸ãkw“ard›¬ anÃŽalys•#i“s,˜high¸ãe• «r-ordÕTe“r˜anÃŽalys•#i“s˜i“s˜impGo•qs“s#ibãŽle,˜so˜w•¸ãe˜nÃŽaiv“ely˜asqsuÜrm“e˜t•Uh“aÀtŽ¡‘Rall–UUušÜrnkno¸ãwn“fu˜nctš¸ãions“do“not“dÕTemÃŽan˜d“t•Uh˜eGir“arguÜrm˜en±Çtàs“aÀt“all.ަ‘aMan•¸ãy›pbac“kw“ard˜a“bqstract˜in±ÇtµUe «rpret“aÀt“ions˜go˜tÜro˜a˜gre•qaÀt˜dÕTe“al˜of˜trou•UbãŽle˜tÜro˜moGdÕTelŽ¡‘RdÜraÀt•¸ãa›’ƒstru“ct“ureGs˜w“ell,˜t•Uh“e «reÕTb“y˜in“d“u“cinÜrg˜cons#idÕTe «ra“b•ãŽle˜comp“liñÆcaÀt•¸ãion˜in˜t•Uh“e˜mÃŽac“hin“e «ryŽ¡‘RwhiñÆcš¸ãh–×dÕTeqals“wit•Uh“dÜraÀt˜a“stru˜ct˜ureGs“{“constru˜ctšÜror“fu˜nctš¸ãions“an˜d“Ácase²s.“F–ÿ*ªort˜uÜrnÃŽaÀtµUely“,Ž¡‘Rt•Uh•¸ãe›YpreGs1Çen±Çt“aÀt“ion˜can˜b•#e˜s“impãŽli eGd˜b•¸ãy˜t•Uh“e˜obqs1Çe «rv‘ÿqÇaÀt“ion˜t•Uh“aÀt,˜pro“vidÕTeGd˜t•Uh“e˜a“bqstrac-Ž¡‘Rtš¸ãion–»nof“Ácase²s“an˜d“constru˜ctšÜror“fu˜nctš¸ãions“ob#eys“ce «rt˜ain“constrain±Çtàs,“it“do#eGsn't“mÃŽaÀt-Ž¡‘RtµUe «r– +p#eš «rformÃŽance“hinÜrgeGs“on“gen•¸ãe˜raÀt“inÜrg–>+smÃŽall“tµUe˜rms“anš¸ãd“k˜eepinÜrg“t•Uh˜em“smÃŽallŽ¡‘Rt••UhroughÃŽouÜrt›/w¸ãell“advi˜s1ÇeGd“tšÜro“str*«iv¸ãe“t˜o•¸ãw“ards–>t•Uhi#s“goal.“As“an“exampãŽle,“Phil“W‘ÿ*ªadle «r's“or*«i-Ž¡‘RginšÃŽal–a"non- aÀt“str*«iñÆctn¸ãeGsqs“an˜alys•#i“s›a"sõTc•¸ãh“em“e‘[W‘ÿ*ªad87Ž‘]˜ga“v“e˜an˜in±ÇtµUe «rpret“aÀt“ion˜of˜ÁcaseŽ¡‘R²expreGsqs#ions–eHwhiñÆcš¸ãh“expan˜ds“expGon˜en±Çt˜ially“witš•Uh“t˜hš¸ãe“s#ize“of“inst˜an±Çt˜iaÀt˜inÜrg“t˜ypš#eGs.“Thi˜sŽ¡‘Rrenš¸ãdÕTe «rs–Ý•it“impract˜iñÆcal“for“all“buÜrt“t•Uh˜e“t˜inieGst“programs“([Sew94Ž‘8ç],“Sect˜ion“5.8).“OurŽ¡‘Rbac•¸ãkw“ards›åf*«ram“ew“oràk˜i#s˜pGoãŽlymorphiñÆcally˜in“v‘ÿqÇar*«ian±Çt,˜so˜it˜a“v“oids˜t•Uh“aÀt˜part“iñÆcularŽ¡‘RhÃŽorror,–×õbuÜrt“it“stš¸ãill“h˜as“pãŽlen±Çt˜y“of“pGotµUen±Çt˜ial“for“o˜pt˜imi#saÀt˜ion“us#inÜrg“a˜bqstract“Álet²s.Ž¡‘RTh¸ãe–vÒpGoin±Çt“of“t•Uhiš#s“exampãŽle“i˜s“tš•Uh¸ãaÀt,“wit˜h“a“litŸÿt˜le“care,“m˜u•¸ãc“h–vÒof“t˜hš¸ãe“\exp•Gon˜en±Çt˜ialn˜e“sqs"Ž¡‘Rcan–UUb#e“enÜrginš¸ãee «reGd“aw˜ay‘ÿ*ª,“givinÜrg“su•Ubqst˜an±Çt˜ial“pš#e «rformÃŽance“b˜en¸ãe tàs.ŽŸ è7‘RÓ4‘ €Re`sulÐtÔËsŽŸÑ‘R»4.1‘ üIn–ÕTt…Th®9e“smº}allŽŸÑ‘R²Th•¸ãe›6wtµUec“hnoãŽlogy˜dÕTe•GsõTcr*«ib#e“d˜aš¸ãb“o˜v˜e–6ww˜as“constru˜ctµUešGd“ins#idÕTe“a“purp˜oqs1Çe-builÜrt“dÕTev¸ãel-Ž¡‘Ro•¸ãpm“en±Çt›-`f*«ram“ew“oràk.˜Th“e˜f*«ram“ew“oràk˜i#s˜a˜quiñÆc“k-an“d-dirt“y˜impãŽlem“en±Çt“aÀt“ion˜of˜t•Uh“eŽ¡‘Rf*«ron±Çt–&Åpart“of“a“compileš «r“for“an“o•¸ãv“e˜rloadinÜrg-f*«ree–&Åsu•Ubqs1Çet“of“Haskš¸ãell,“dÕTe•Gs#ign˜e“d‘&ÅtÜroŽ¡‘Rf•#acilitš¸ãaÀtµUe‘Ÿúexp“e• «r*«im˜en±Çt˜aÀt˜ion.‘ŸúA‘Ÿ¤high˜e“r-ordÕTe“r–Ÿúremo˜v‘ÿqÇal“transformÃŽaÀt˜ion“in“t•Uh˜e“st˜yleŽ¡‘Rof–³LNelan‘[Nel91Ž‘¸ç]“allo¸ãws“ r•s“t-ordÕTe «r–³LanšÃŽalys1ÇeGs“of“programs“m˜akinÜrg“su•Ubqst•¸ãan±Çt“ial‘³Lus1ÇeŽ¡‘Rof›Áhigh¸ãe• «r-ordÕTe“r˜fuÜrnct•¸ãions.˜All˜anÃŽalys1ÇeGs˜w“e «re˜don“e˜monomorphiñÆcally‘ÿ*ª,˜tÜro˜mÃŽak“eŽ¡‘Rcompar*«i#son–¶Ûwit•Uh“a“forwš¸ãard“in±ÇtµUe «rpret˜aÀt˜ion“f#aire «r.“F‘ÿ*ªor“t•Uh˜e“bac˜kw˜ards“anÃŽalys1ÇeGs,Ž¡‘Rof–Lþcours1Çe,“t•Uh¸ãe «re“iš#s“no“in±Çtr*«ins˜išñÆc“reqason“tÜro“us1Çe“monomorphi˜c“anÃŽalys•#i“s.–LþF‘ÿ*ªour“inpuÜrtàsŽ¡‘Rw¸ãe «re‘UUus1ÇeGd:ŽŸgÛ‘X@»{ŽŽŽ‘cÁavlTree²:–UUins1Çe «rtš¸ãion“of“itµUems“in±ÇtÜro“an“A‘þãVL“tree“(44“lin˜eGs).ަ‘X@»{ŽŽŽ‘cÁlife²:›XÔLaŸÿuÜrnc•¸ãh“bury's˜impãŽlem“en±Çt“aÀt“ion˜of˜Con“w“ay's˜\life"˜s#im•UulaÀt“ion˜(311˜lin“eGs).ަ‘X@»{ŽŽŽ‘cÁfft²:–ðF‘ÿ*ªast“fourš*«ie «r“transform,“f˜rom“HartšµUel's“b#enc¸ãhmÃŽaràk“suit˜e‘[HL92aŽ‘À]“(421Ž¡‘clin¸ãeGs).ަ‘X@»{ŽŽŽ‘cÁida²:–UUSoãŽlvš¸ãeGs“t•Uh˜e“15-puzzle,“also“f*«rom“HartšµUel's“suit˜e“(728“lin¸ãeGs).ŽŸMä‘aÁlife²,–M™Áfft“²anš¸ãd“Áida“²are“su•Ubqst˜an±Çt˜ial“inpuÜrtàs.“QuotµUešGd“s#ize˜s“are“aftµUeš «r“ins1Çe˜rt¸ãion“ofŽ¡‘Rsuit•¸ãa“bãŽle–iÑpreludÕTe“fuÜrnctš¸ãions.“Th˜ey“mÃŽak˜e“su•Ubqst˜an±Çt˜ial“us1Çe“of“high˜e• «r-ordÕTe“r‘iÑfuÜrnct˜ions,ŽŽŽŒ‹„ gÌ\ ý¯3¤ 2Ì\ þjߌ͟ä?þ’—«†ÑF‘ÿÌorw´CardsŽŽ’à°Ev‘ÿh‰alT‘ÿÌransŽŽ’ ‹wHeKadStr-qiðÚctŽŽŽ¤ ‘Z˶ÐProgram‘H‡ŸLÏ„ ff‘™š„ ffŽ’\–Tim¾9e‘H‡ŸLÏ„ ffŽ’¸gÌReAÇs äid‘H‡ŸLÏ„ ff‘™š„ ffޒܤøTim¾9e‘H‡ŸLÏ„ ffŽ’ý¹ReAÇs äid‘H‡ŸLÏ„ ff‘™š„ ffŽ’!EåTim¾9e‘H‡ŸLÏ„ ffŽ’A©¦ReAÇs äidŽŽ‘YePŸ³5‰ffUŸ³1‘keÜavlTreeŽ‘(ÌŸLÏ„ ff‘™š„ ffŽ‘;V`Ð9.58‘H‡ŸLÏ„ ffŽ‘c,É1514‘H‡ŸLÏ„ ff‘™š„ ffŽ’‡žÂ0.23‘H‡ŸLÏ„ ffŽ’¬"öó3¼j‘¹ cmti9Þ197‘H‡ŸLÏ„ ff‘™š„ ffŽ’Ì?¯Ð0.27‘H‡ŸLÏ„ ffŽ’ðÃãÞ200ŽŽ¡‘ ÆÜlifeŽ‘(ÌŸLÏ„ ff‘™š„ ffŽ‘2dÐ359.20‘H‡ŸLÏ„ ffŽ‘^ŒË11203‘H‡ŸLÏ„ ff‘™š„ ffŽ’‡žÂ2.01‘H‡ŸLÏ„ ffŽ’¬m´628‘H‡ŸLÏ„ ff‘™š„ ffŽ’Ì?¯2.97‘H‡ŸLÏ„ ffŽ’ðÃãÞ615ŽŽ¡‘ Þ‘ÜfftŽ‘(ÌŸLÏ„ ff‘™š„ ffŽ‘6¶bÐ28.76‘H‡ŸLÏ„ ffŽ‘bÉ!Þ1473‘H‡ŸLÏ„ ff‘™š„ ffŽ’‡žÂÐ6.38‘H‡ŸLÏ„ ffŽ’§jÞ1473‘H‡ŸLÏ„ ff‘™š„ ffŽ’Ì?¯Ð8.38‘H‡ŸLÏ„ ffŽ’ì ûÞ1524ŽŽ¡‘ Þ‘ÜidaŽ‘(ÌŸLÏ„ ff‘™š„ ffŽ‘6¶bÐ920+‘H‡ŸLÏ„ ffŽ‘W[54000+‘H‡ŸLÏ„ ff‘™š„ ffŽ’‡žÂ9.32‘H‡ŸLÏ„ ffŽ’§jÞ1725‘H‡ŸLÏ„ ff‘™š„ ffŽ’Ì?¯Ð7.70‘H‡ŸLÏ„ ffŽ’ì ûÞ1734ŽŽŽŽŽŸ:³3‘,ÑT‘ÿÌa´Cbá´le‘†1.–¬ßÐPš¾9e ÞrformÈance“of“a˜bNs”tract“in·¤t•ºîeš Þrpret“e˜r”s›¬ß(t•¾9im“e˜in˜s. econ“ds,˜re•AÇs äid؇encie“s˜in˜Kb¾9ytºîe“s).ޤ ‘,It¾9aliò×ci äs. e•AÇd›®2 gure“s˜in¾9diò×caÄÍtºîe˜p äeNak˜re“s äid؇encie“s˜d؇e n¾9e“d˜b¾9y˜prepro“ce“sNs äinßg˜ph¾9as. e“s,˜raÄÍt•Th¾9e Þr˜t“h¾9anŽ¡‘,a•¾9bNs”tract›í>in·¤tºîe Þrpret“aÄÍt“ion˜or˜ xpAÇoin·¤t“inßg.˜Th“e˜ÑF‘ÿÌorw´Cards˜ÐanÈalys• äi“s˜of˜Üida˜Ðdid˜not˜compå±letºîeŽ¡‘,evš¾9en–Tin“54“m˜ega˜b˜ytºîeAÇs“of“h˜eNap.ŽŽŸ"ó‘,²whiñÆc•¸ãh›;vt•Uh“e˜ r•s“t•¸ãi e «r˜h“as˜tÜro˜w“oràk˜quitµUe˜h“ard˜tÜro˜remo“v“e,˜an“d˜whiñÆc“h˜caŸÿus1ÇeGs˜t•Uh“e˜inpu•Ürt˜t“oޤ ‘,t•Uh•¸ãe›ä7a“bqstract˜in±Çt•µUeš «rpret“e˜r–ä7pro¸ãp#e˜r“tÜro“bš#e“cons˜idÕTeš «ra¸ãbãŽly“bigge˜r“tš•Uh¸ãan“t˜hš¸ãe“uÜrn±Çtransform˜eGdŽ¡‘,sourceGs.Ž© ¦ê‘;Thš¸ãe–pNanÃŽalys1Çe «r“w˜as“wr*«itŸÿtµUen“in“st˜an˜dÜrard“Hask˜ell“1.2,“compileGd“wit•Uh“Glasgo˜wŽ¡‘,Haskš¸ãell–bS0.19“\Á-O²",“an˜d“ruÜrn“on“a“quiet“64-m˜ega˜b˜ytµUe“SušÜrn“Sparc“10/31“ru˜nnin˜gŽ¡‘,SuÜrnOS–v4.1.3.›vOA“gen•¸ãe «raÀt“ionÃŽal˜garbage˜coãŽllectÜror˜w“as˜us1ÇeGd,˜an“d˜h“eqap˜s#izeGs˜w“e «reŽ¡‘,s1Çet–yetÜro“try“anš¸ãd“k˜eep“garbage“coãŽllect˜ion“coqstàs“b#elo˜w“10%,“alÜrt•UhÃŽough“for“large «r“reGs-Ž¡‘,idÕTencieGs–Î.t•Uhiš#s“i˜s“diculšÜrt.“Tim¸ãeGs“u˜nš¸ãdÕTe «r“s#ixt˜y“s1Çecon˜ds“are“a˜v˜e «rageGd“o˜v˜e «r“s#ix“ruÜrns.Ž¡‘,Thš¸ãey–KfincludÕTe“t•Uh˜e“prepro•Gce“sqs#inÜrg‘Kft˜im˜e“s–Kfof“pars#inšÜrg,“dÕTeGsugar*«in˜g,“t•¸ãyp#ec“h“ec“kin˜g,‘Kfmono-Ž¡‘,morphi#saÀt•¸ãion›gžan“d˜ r•s“t•¸ãi caÀt“ion,˜buÜrt˜in˜no˜cas1Çe˜do˜t•Uh“e•Gs1Çe˜excee“d˜20%˜of˜t•Uh•¸ãe˜tÜrot“al.Ž¡‘,T‘ÿ*ªa•¸ãbãŽle‘1›UUshÃŽo“ws˜t•Uh“e˜reGsul•Ürtàs,˜us#in“g˜t•Uhree˜di e «ren•±Çt˜a¸ãbqstract˜in“tµUe «rpret•¸ãaÀt“ions:ŽŸ›¨‘2@»{ŽŽŽ‘=He µadStr1iï¥ct²:–‘a“hš¸ãeqad“str*«iñÆct,“bac˜kw˜ards“in±ÇtµUe «rpret˜aÀt˜ion“preciš#s1Çely“as“dÕTe•GsõTcr*«ib˜e“dŽ¡‘=in–UUt•Uhiš#s“pap˜e «r.ަ‘2@»{ŽŽŽ‘=Ev‘ÿ\ralT‘ÿ «rans²:–¼–anot•Uhš¸ãe «r“bac˜kw˜ards“in±ÇtµUe «rpret˜aÀt˜ion,“form˜eGd,“as“wit•Uh“HeqadStr*«iñÆct,Ž¡‘=us#inÜrg–'kt•Uhš¸ãe“gen˜e «rš*«iñÆc“f˜ram•¸ãew“oràk‘'kdÕTe•GsõTcr˜ib#e“d‘'kaš¸ãb“o˜v˜e,–'kbušÜrt“us#in˜g“a“s#impãŽleš «r“c•¸ãh“aractµUe˜r-Ž¡‘=i#sašÀt¸ãion–Sof“dÜra˜tš¸ãa“stru˜ct˜urešGs,“e˜sqs1Çen±Çtš¸ãially“a“gen˜e «rali#saÀt˜ion“of“Geo “Bur#n's“Ev‘ÿqÇalu-Ž¡‘=aÀt•¸ãion‘UUT‘ÿ*ªransform“e «rs.ަ‘2@»{ŽŽŽ‘=F‘ÿ «orw®9ards²:–Àa“forwš¸ãards“BHA-st˜yle“in±Çt•µUeš «rpret“e˜r,–Àwit•Uh“h•¸ãan“dlinšÜrg–Àof“d˜aÀtš¸ãa“stru˜c-Ž¡‘=t¸ãurešGs–Çtas“dÕTe˜sõTcr*«ib#e˜d“in‘[Sew91Ž‘8ç].“Thš¸ãe“dÜraÀt˜a-stru˜ct˜ure“h˜an˜dlinÜrg“can“bš#e“cons˜idÕTe «reGdŽ¡‘=in–UUa“s•1Çens“e–UUof“\equiv‘ÿqÇalen±Çt"“dÕTetš¸ãail“tÜro“t•Uh˜aÀt“of“Ev‘ÿqÇalT‘ÿ*ªrans.ŽŸô¾‘,Eac¸ãh‘–in±Çt•µUeš «rpret“e˜r––wš¸ãas“m˜eqasurešGd“wit•Uh“a“rewr*«itµUe-bas1Çe˜d“ xp˜oin±ÇtµUe «r“dÕTe˜s#ign¸ãe˜d“sp#eciallyŽ¡‘,for–®±it.“Thš¸ãe“rewr*«itµUe «rs“are“v˜e «ry“s#imilar,“an˜d“b˜y“us#inÜrg“t•Uh˜e“sam˜e“kin˜d“of“o˜pt˜imi#saÀt˜ionsŽ¡‘,in–UUeqacš¸ãh“w˜e“hÃŽo˜p#e“tÜro“mÃŽak˜e“t•Uh˜e“compar*«i#son“reqasonÃŽa˜bãŽly“f#air.ަ‘;Th•¸ãeGs1Çe›Ù1m“eqasurem“en±Çtàs˜mÃŽak“e˜cleqar˜just˜wh“aÀt˜an˜adv‘ÿqÇan±Çt“age˜t•Uh“e˜bac“kw“ards˜in±ÇtµUe «r-Ž¡‘,pret•¸ãaÀt“ions›/h“a“v“e˜{˜t•Uh“e˜Ev‘ÿqÇalT‘ÿ*ªrans˜anÃŽalys•#i“s˜of˜Álife˜²ruÜrns˜almoqst˜t•¸ãw“o˜h•UuÜrn“dreGd˜t“im“eGsŽ¡‘,f#astµUe «r–6©tš•Uh¸ãan“t˜hš¸ãe“forw˜ards“anÃŽalys•#i“s,–6©an˜d“in“a“f*«ract˜ion“of“t•Uh˜e“space.“Th˜e“HeqadStr*«iñÆctŽ¡‘,in±ÇtµUe «rpret•¸ãaÀt“ion–-iš#s“not“s˜igni can±Çtš•Uly“slo•¸ãw“e «r‘-t˜h“an‘-t˜h“e–-Ev‘ÿqÇalT‘ÿ*ªrans“v¸ãe «rsš#ion.“Thi˜s“com¸ãeGsŽ¡‘,as–'a“bit“of“a“surpr*«iš#s1Çe,“s˜ince“onš¸ãe“migh˜t“exp#ect“it“tÜro“proGd˜u˜ce“m•Uu˜c˜h“more“dÕTet˜ail,Ž¡‘,an•¸ãd›l¿t“ak“e˜corre•Gsp“on¸ãdin•Ürgly˜lon“ge «r.˜Insp#ect¸ãion˜of˜ou“tʪpu“tàs˜rev•¸ãeqals˜t•Uh“aÀt˜it˜do#eGsn'tŽ¡‘,alw•¸ãays›ap n“d˜a˜gre•qaÀt˜dÕTe“al˜more˜str*«iñÆctn¸ãeGs“s˜t••Uh¸ãan˜t“h¸ãe˜Ev‘ÿqÇalT‘ÿ*ªrans˜anÃŽalys•#i“s.˜An¸ãd˜quitµUeŽŽŽŒ‹*. gÌ\ ý¯3¤ 2Ì\ ýäÜš‘R²wh•¸ãy›²t•Uh“e˜HeqadStr*«iñÆct˜anÃŽalys•#i“s˜shÃŽould˜som•¸ãet“im“eGs˜b#e˜quiñÆc“k“e «r˜(for˜Áida²)˜i#s˜m“ystµUe «r*«ious,ޤ ‘RpGo•qs“s#ibãŽly–UUdš¸ãue“tÜro“t•Uh˜e“preci#s1Çe“dÕTet˜ails“of“reGd˜u˜ct˜ion“paÀtš•Uhs“in“t˜h¸ãe“tšµUe «rm“rewr*«it˜e «rs.Ž©qm‘R»4.2‘ üIn–ÕTt…Th®9e“largeŽŸqm‘R²Aft•µUe «r›Žext“ens#iv•¸ãe˜t“u•Ürnin“g˜in˜t•Uh•¸ãe˜dÕTev“elo“pm“en±Çt˜f*«ram“ew“oràk,˜t•Uh“e˜(pGoãŽlymorphiñÆc)˜Heqad-Ž¡‘RStr*«iñÆct‘y}in±Çt•µUeš «rpret“e˜r–y}an¸ãd“itàs“ xpGoin±ÇtµUe˜r“w¸ãe˜re“instš¸ãalleGd“in“Glasgo˜w“Hask˜ell“0.19“tÜroŽ¡‘Ras•qs1ÇeGs“s–¹+t•Uhš¸ãe“via˜bilit˜y“of“su˜c˜h“str*«iñÆctn˜eGsqs“anÃŽalys•#i“s–¹+\in“t•Uh˜e“large".“In±ÇtµUegraÀt˜ion“addÕTeGdŽ¡‘Raš¸ãbGouÜrt–¯¨5700“non-bãŽlank,“non-comm˜en±Çt“lin˜ešGs“of“co˜dÕTe“tšÜro“an“exi#st¸ãin˜g“t˜otš¸ãal“of“a˜bGouÜrtŽ¡‘R50000.–]BecaŸÿus1Çe“t•Uhš¸ãe“compile «r“i#s“w˜ell“dÕTe•Gs#ign˜e“d,–]in±ÇtµUegraÀt˜ion“w˜as“remÃŽaràkñÆa˜bãŽly“cleqan,Ž¡‘Rwit••Uh›Èt“h¸ãe˜smÃŽalle•Gst˜of˜mo“di caÀt•¸ãions˜tÜro˜exi#st“inÜrg˜coGdÕTe.˜Th“e˜exi#st“inÜrg˜f*«ram“ew“oràk˜forŽ¡‘RtransmitŸÿt•¸ãinÜrg›=-pragmÃŽaÀt“iñÆc˜informÃŽaÀt“ion˜b#et“w“een˜mošGd“ule˜s›=-w“as˜extµUen“dÕTeGd˜tÜro˜allo“w˜fullŽ¡‘Rin±ÇtµUe «rmoGd¸ãule›ž\anÃŽalys•#i“s;˜giv•¸ãen˜t•Uh“e˜arguÜrm“en•±Çtàs˜prešGs1Çen“tµUe˜d–ž\in“Sectš¸ãion‘2,“t•Uh˜e“exp#e «r*«im˜en±ÇtŽ¡‘Rw•¸ãould›UUh“a“v“e˜b#een˜largely˜w“ort•UhleGsqs˜h“ad˜t•Uhi•#s˜b“een˜omitŸÿtµUeGd.Ž¡‘aCompilinÜrg– ¾Glasgoš¸ãw's“impãŽlem˜en±Çt˜aÀt˜ion“of“t•Uh˜e“Hask˜ell“ÁPrelude²,“pãŽlus“som˜e“ot•Uh˜e «rŽ¡‘Rgen¸ãe «ral-purp•Goqs1Çe›Iølibrar*«ie“s,˜t•Ürot¸ãallin“g˜a¸ãbGou“t˜4000˜lin•¸ãeGs,˜t“ak“eGs˜som“e˜four˜hÃŽours˜on˜aŽ¡‘RSuÜrn›·«SparcSt•¸ãaÀt“ion˜IPX,˜roughly˜a˜dou••UbãŽlinÜrg˜of˜t“h¸ãe˜no-anÃŽalys•#i“s˜t•¸ãim“e.˜A‘·‘h“eqap˜s#izeŽ¡‘Rof–bT24“m•¸ãega“b“ytµUešGs‘bTpro“v“e˜d–bTmore“t•Uhš¸ãan“adÕTequaÀtµUe,“an˜d,“pãŽleqas#inÜrgly‘ÿ*ª,“t•Uh˜e «re“w˜as“no“n˜eeGdŽ¡‘RtšÜro–ijreGsort“t˜o“t•Uh¸ãe“tree-pru˜nin˜g“dÕTe•GsõTcr*«ib#e“d–ijin“Sectš¸ãion‘3.3.“An“eqarlie «r“v˜e «rs#ion“of“t•Uh˜eŽ¡‘RanÃŽalys1Çe «r,–s€in“itšàs“dÕTev•¸ãelo“pm“en±Çt‘s€f*«ram“ew“or˜k,‘s€const“it“ušÜrt“in˜g–s€13000“lin¸ãešGs“in“28“mo˜d¸ãule˜s,Ž¡‘Rw¸ãas›‹®su••Ubqs1Çequen±Çt“ly˜compile•Gd.˜25˜mo“d¸ãule“s˜w¸ãen±Çt˜t••Uhrough˜wit“h˜no˜probãŽlems,˜whilstŽ¡‘Rt•Uhree–UUrequireGd“pru•Ürnin“g.Ž¡‘aBy–t7anš¸ãy“st˜an˜dÜrards,“su˜c˜h“exp#e «r*«im˜en±Çt˜aÀt˜ion“wit•Uh“reqal“compile «rs“an˜d“reqal“pro-Ž¡‘Rgrams–glenš¸ãds“mÃŽa‘Ž8jor“creGdibilit˜y“tÜro“t•Uh˜e“en•Ürgin˜ee «rš*«in“g‘gdÕTe•GsõTcr˜ibš#e“d–gin“t•Uhi˜s“pap˜e «r.“Ob-Ž¡‘Rs1Çe «rv‘ÿqÇaÀtš¸ãion–\of“t•Uh˜e“in±Çt•µUeš «rpret“e˜r–\an¸ãd“ xpGoin±ÇtµUe˜r“grap¸ãpãŽlinšÜrg“wit•Uh“non-t˜o¸ãy“inpu˜tàs“leqad“t˜oŽ¡‘RmÃŽan•¸ãy›5Hre n“em“en±Çtàs,˜an“d˜tÜro˜t•Uh“e˜suggeGst“ions˜for˜furt•Uh“e «r˜dÕTev“elo“pm“en±Çt˜tÜro“w“ards˜t•Uh“eŽ¡‘Renš¸ãd–UUof“Sect˜ion‘3.4.ަ‘R»4.3‘ üConclus(äionsŽŸqm‘R²Th•¸ãe›`»a“bqstract˜in±Çt•µUeš «rpret“e˜r–`»anš¸ãd“ xpGoin±Çt˜inÜrg“m˜ec˜h˜ani#sm“ouÜrt•Ulin˜eGd“a˜bGo˜v˜e“h˜a˜v˜e“b#eenŽ¡‘RdÕTev•¸ãelo“p#eGd›Xan“d˜t“uÜrn“eGd˜b“y˜ru•Ürnnin“g˜t•Uh•¸ãem˜o“v“e «r˜ap“pro“ximÃŽaÀtµUely˜t“w“en±Çt“y˜t•UhÃŽousan“d˜lin“eGsŽ¡‘Rof–Q½Hask¸ãell“source“cošGdÕTe.“As•qs1Çe˜s“s#inÜrg–Q½t•Uhš¸ãe“via˜bilit˜y“of“n˜ew“sõTc˜h˜em˜eGs“only“on“smÃŽall“ex-Ž¡‘RampãŽleGs–Œor“usš#inÜrg“pap˜e «r“anÃŽalys1ÇeGs“can“b˜e“mi˜sleqadinšÜrg.“Go•Go“d–Œen˜gin¸ãee «r*«in˜g“requireGs“notŽ¡‘Ronly›F‘sup•¸ãpGort“inÜrg˜t•Uh“eory˜{˜of˜whiñÆc“h˜t•Uh“e˜ eld˜shÃŽo“ws˜no˜shÃŽort“age˜{˜buÜrt˜also˜extµUens-Ž¡‘Riv•¸ãe›8quan±Çt“it“aÀt“iv“e˜anÃŽalys•#i“s˜on˜reqali“st¸ãiñÆc-s“izeGd˜inpuÜrtàs.˜Th•¸ãe˜relaÀt“iv“e˜lac“k˜of˜e ect“iv“eŽ¡‘RimpãŽlem•¸ãen±Çt“aÀt“ions–Iof“str*«iñÆctnš¸ãeGsqs“an˜d“ot•Uh˜e «r“s1ÇemÃŽan±Çt˜iñÆc“anÃŽalys1ÇeGs“for“Hask˜ell“highligh˜tàsŽ¡‘Rt•Uh•¸ãe›UUn“eeGd˜for˜furt•Uh“e «r˜aÀtŸÿtµUen±Çt“ion˜t•Üro˜en“gin¸ãee «r*«in“g˜i#s•qsueGs˜in˜a¸ãb“stract˜in±ÇtµUe «rpret•¸ãaÀt“ion.Ž¡‘aUs#inÜrg–Yçt•Uh¸ãešGs1Çe“pr*«incipãŽle˜s,“a“p˜oãŽlymorphiñÆc“pro‘Ž8jectš¸ãion“anÃŽalys1Çe «r“for“Hask˜ell“h˜as“b#eenŽ¡‘RcreqaÀtµUeGd.–ÇThš¸ãe“anÃŽalys1Çe «r“i#s“e ect˜iv˜e,“robust,“relia˜bãŽle,“t˜urš#ns“in“go•Go“d‘Çp˜e «rformÃŽance“s,Ž¡‘Ran•¸ãd›«—h“as˜b#een˜us1ÇeGd˜tÜro˜sup“p•Gort˜re“s1Çeqarc¸ãh˜in˜aŸÿu•Ürt“omÃŽaÀt¸ãi•ñÆc˜str*«i“ct•¸ãi caÀt“ion˜of˜Hask“ellŽ¡‘RprogramsŸü^ÿ±4ŽŽ‘|s².–´QIt“also“lays“ouÜrt“a“dÕTeGsš#ign“wit•Uh“cons˜idÕTe «raš¸ãbãŽle“pGotµUen±Çt˜ial“for“re n˜em˜en±Çt,Ž¡‘Rpart¸ãiñÆcularly–í¶wit•Uh“reGsp#ect“tšÜro“buildin˜g“more“economiñÆcal“aš¸ãbqstract“in±ÇtµUe «rpret˜aÀt˜ions,Ž¡‘Ran¸ãd–GÄtšÜro“ xin˜g“sh¸ãar*«in˜g“probãŽlems“in“t•Uhš¸ãe“ xpGoin±Çt˜inÜrg“m˜ec˜h˜ani#sm.“F‘ÿ*ªurt•Uh˜e «r“dÕTev˜elo˜pm˜en±ÇtŽ¡‘RmÃŽay–UUyield“impreGsqs#ivš¸ãe“str*«iñÆctn˜eGsqs“an˜d“sh˜ar*«inÜrg“anÃŽalys1ÇeGs“for“Hask˜ell.Ž‘RŸä‰ff8çÏŸ LÍ‘Ÿü-=Ô4ŽŽ‘ ?üÐDeni äs›THo•¾9w“e,˜Depart“m“en·¤t˜of˜Compušßt“in˜g,–TImp äe Þr'xial“Coå±llege,“Lon¾9don.ŽŽŽŒ‹A  gÌ\ ý¯3¤ 2Ì\ ýäÜš‘,ÓRefefrence`sŽŸ#f‘,Ð[AFMŸü-=Ô+Ž‘nÐ95]ŽŽ‘ZóxZenÈa–Ð'Ar'xioå±la,“MaÄÍt§3tThias“F‘ÿ:«elleAÇiš äs. en,“John“Marai˜sš”t,“Mart¾9in“Od؇e Þr˜sky‘ÿ:«,“an¾9d“Philipޤ ‘Xa²W‘ÿ:«adle Þr.‘MA‘Øocall-b•¾9y-n“ee•AÇd›Ølam†Pb“dßa˜calculus.‘MIn˜Þ22nd–USymp‡osium“on“PrinciplesŽ¡‘Xa²of›6ˆPr•‡o“gr“amming˜L“anguagesÐ,–û‰San“F‘ÿ:«ranciš äsö!co,“Califor˜nia,“JanTuary“1995.“A¾9CMŽ¡‘Xa²PreAÇsNs.Ž¡‘,[A‘ÿ|rug93]ŽŽ‘Xa²LennÈart›¯LA‘ÿ|rugus”tâfsNson.‘ä¢Impå±lem•¾9en·¤t“inßg˜h“ask“ell˜o“v“e Þrloadinßg.‘ä¢In˜ÞPr•‡o“c“e“e“dings‘Û¹ofŽ¡‘Xa²the–¶ïF‘ÿJªunctional“Pr•‡o“gr“amming›¶ïL“anguages˜and˜Computer˜AÃŽr“chite“ctur“e˜Confer-Ž¡‘Xa²enc•‡e,›N cmmi10ó 0e—rcmmi7óKñ`y cmr10óÙ“ Rcmr7óú±u cmex10ùÊßßßßßßßbz2-1.0.0.1/test/data/sample2.bz20000644000000000000000000022000407346545000014405 0ustar0000000000000000BZh21AY&SY|1Éaƒýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿá= ï}ƒÎç”`  hÐ6®¼J£ÛܰW@묻Õ(e€NÆŽùÝè÷®9h '|sßîŒà °ØP xÖM®î­»€áz:<{¢·aîϯrÞ’÷—Üìߦ£³H†­·;ΩTóéÝöø>ûw‡zó›löîØ8X¸µlõ=m&ÌR÷=7¾r¯²Úßsà>ï¼%]àg9¾Þ÷£`ÙUlØ ‚‚É€7¹Þûwv¾¼@è`;{{fAX:à—]÷zö:jfõrí]dkƒ£Üd ½ÊÛ|ìŸ{}»0KíqœîªoZð|´¤}•¹'cå9åTï+ãŽ(>ξöÛEsw5¯»A´Üwݽõ«ïvw´ Q ½÷·Å¾ï<õ½íÞŘ»tuêvÀûbMY6ûo|ïZuJ·®µö¶Þ}Õï•§³««»“‡0îÑÎà쌭ï€uñ¯+]ãÜct˜ûÛ£7Ý›€ë¶ITÝÍÖݾ&ùêîwB¨4^óï£p=cu÷·»ë¶Õ®øLîzè= ÕµïXˆˆhª}ï>½ÖGÒÐØ]:‹UõË9ï´ÀK_ú€Qs¾Ñmßs‚½ofß+åwÛˆ$ZtW|ÞçgÖò*vη½ÜÞëotë×vÁõÛíÝëÝVHhz*€@t&À:t £@ ”,×@Ž÷ß|”õ÷tß#ƒëPi±áïl9àáò>ßÅ@)ê«%æàÑA@°„# }^rº€ž†šB&†€`ÓL!“&F€4Èɦ4ÓMF€ )í”Í 4˜ƒSÈ! 124Ñ=)àIêy Ñè3Iä(ôFFž¦ž§¨h€z€ÈC&€=F†€€ h‚H„È ¦€„U<ÚIíS#ODÓÒŸ‰&žS'êCÊ~¤õ4zž“õOQåQšž4i²ž6‘“F5ЦÔ4ôšiê¡£'“P õG©ê=F›PbhÐÑ “Õ)MDžÒžÒ¦Ò§êž§éOHõ‘¦#Ô44MIêd  € Ô€F™€$„ ¦ÐÒfC@ 42M…0jShM¦ª~ƒM5Sð§“…Oz'‘0ž§¦“Ú4ÒŸ”ÍSÚ?ЛJy¥?I‰Œ€¨$ÔH @&†‰„CM4ÓMLðši‰MäÂhÅ4õ=4&ÑM©êŸŠŸ©êžfLÕ=0‰úi1©´š‰ïTÔ~IèÄSØ#Ô5OÔôž†OD&›*~ž•=5?Ò§äÔÓLŒM0q D’$Ê—2léô(Ò§QSUWY[]QSUWY[]Y]Z ס|8pß0†þ­«6Íg„ä‰âHKô- z—§€ûS†¹A(ªLãÔXƒûëc4I>åöþq[-/»v¾ëkwSb)˜À¢Œn©c:6¶8ÞvH`|ÿÕÒŸ'9í¼6ooòoæ·DQ+“’{ÏSêm­ŸÜCSßкÈ+Ê•ò4«{Æû¯Áê2(ù³qdôÐ59®=ÐîÏ¡Ï<•qž(3ÝX¡óId÷R>4\nJÑ”V %ø@ÌüçeDVø(‰ªŠƒtV®Øâ¸I8xç‘Oz?¶&t¸íá9Z…Núš DúØ<ŠñÀϵôüìóBRŽ"œ¶–)]WþÅèR!E¦Ù¶Ìh¿:ª€"ÁaûÀû¬DzW65¥ý¿X¸K^yÕ¼hŠª2˜¡b°\4Ÿ‚œ4 Ñ´É- ª)PP0þ*R ³ã6~s0—±ÿ³»„Wÿ„'¢Dnü}•¶ñÏR“ò3æ³ÿ6»Þ¶p’6Ó']¬eoÊ Pu·“N2:ï‘í Ç~«F¢ÒTdP)ꄉ+n Và£ÐÙë©Ê‘§‘¹²…ó̱¹¬–HÔr9lC{"`Ì‘ŒŽ·"‚ààÞBc’AR}û ÚÆHå&äK§[šQ—+œå™Î9uwuÝ» 2¹zó…wpŠLówMݻเyÚ.F‘º>»Ë­×;ø_å:¼éæLH™ÝrÎq.í¹$Üîî¾+žNsêþfÕ¯ðji½^ÞÆK»µÝvæíÝÒK»¢ÝÛ°cšì1°)f\¸ÒÌܺÐÐck®è­s$•ј²Q®m®‡fìÕe£EFç`P¦4SlÛdØ¢Žt´Ù!.sºæ¹\¢åp¢ŠM25÷•eº^w‹•9rs¥s¹Ô—èâñrº±Rºwoþ\ÉwÄ¢’]Û˜ˆ;»›“¸Ž”R ºéWŽ:ÎèÌѲ\ªwFÄ–œ»)¹Ãêµç~IxÞˆ6ôº ä F2™)¦’(£HPÿåÿN/ãoßs„[ºèîº~>q‚;|ß/W—ï¯kÀwRoâ¿»ÿGÏ7¶å·.·"s¬î#sA£èw—[æxÄD2‹ÎèÇ.›»ô:?×}×뾫Å3àᱜ·#£»ºìsºŠb§ãÕ*¡uP.Ë«Ž¿GRÓkBöä£G.îܨ×wNësn—f’å¸îÖæé‘õ:ï;_j¼y×ÍåÔŒ„<í\®WL™4C›°dÜè‚NídçÓMÊŠ¾²¹Þ¸¯3»§u­%vôþ'Ï=-ÓEÎZW±lD‘ë€ëfzzð¦@ê–`Üñ0 Ã?ëZL§ïÜß_×M¤¾…vnmÍ}^¸¢Áï¸ÁzEpØ·Ÿ[ýåzF½5IM**öVÑAå­X| ~¦x?°Ò)&Ÿ~£™ÿ3ù^Îz>èç)<™ˆ¾9q#( p(#|(BAz釕+:) ¢Ã'CÓœ%™åFih%H$>ÕGó®gÂjd¯ É| sƸõ>s¿ü—°ÎË‘ÁrK›KÈÆù²°¬‘³îže|µDû,²ìš¸èBßp5EûÿÙbqMp ’Ú”q~›÷k.^Lð" RDtò}ž&ïû‡/ÄdÏr¾.Ê ò‹H[“Õ¨)«G›€¬‰ 2°AvØêª´ëÌñy˜¿wº¶ÇÈoûMéÃ-·ît–OXüÒhEC;æ-jVxÛ›î¼Rïáá3ïnšDAç‰h€Ý>_;ë¹>Ó"æ7þ8Š!ó—QzgS+í€ ¤…÷ª¶³Cë[ DBqô-|œY'k¸ó?Ã0öÝ4)‘3 ž±g¿z#„Ï.êÕLþýhÊó±-/ˆâä[ã44°$h hBu­)Åêõ÷ã1P}¯CUõ}Ÿ/pb™±ÿröÈAóÈ;|¶©£˜ÁV›šÕïÙ_ò¥ÝÕ{£ü”ÉT)¤P¯T¸ƒàƒøƒƒ²÷/òÆQ¬ÌõŽk\Bðvöܹ¬:";äêl”Š ë͇Ôö9ŠdŽBJØ…ܽÙA•ˆo*Êgs™¢QˆÙ‘¤I¤à3êZ[íMžUrøŽˆb€?{¡Ãùr7Ýå»ÏÎ¯Ñ „L¨A,T̃3µÞ¹oYIÅ葽Jd‘IÀšÖ'7÷}мïÓÒáúÏ€x@"?.ØÄ[™À6u6ž×ÙRïÿxû,­[½ávu@j&®=µ4¾ÊŨ_8=€… bçóîu¼(šÅÈ‘ôjùïñ¼¤:‹+¥Vf¥}ÃuÖŠ©Ëx'†×d¾<˜í!zJÉÃä7ïÉÓ2¯ù›§ pˆ(A¬ðñ}EÝPí!¯2ÉžlæÅ[Gý…dnǸlÙé›,.7ê‡Éó^@•‘ÿ2£—d¾æ T„GšÕži×™aÿNÌÀ׫3MjPi·o¾üþ>Ã=šûéúpDADi"“¦#$²]þç‹©¼ó—^xÝ/áœ<ízÐhA4•^ÿ?Ûâ6òc£”®TîVNx™US•M0S¾6ƒ¿„"x-•,Ä~ò=¾ƒ©1Gü“ÛŸ»s?“ï „¤Çö…«/úFÛÆ¶ÿßû^—Ÿa$M! h%Üÿæ‘zKVB`¡¾GN–â´~ÎÆo™ü®ZÒ –Û2Ìg³##4+• ä*Z°´PVµß{þäe¸où„$ &`î‹\âr-Ô€ðæª4ÞUô°}<Ü {ÄÚýUßÁŠ¿v•YÈoþE®Q“ûK%mòüÿ¶Ó9úy_V–9I鲯Ú0~þ½;­ ì×P°š÷{ïý²þÇG†DDa” üÒ € $4$PØS“)¼Ñ¹è_£âié ûΫÚ«–í/›°@ÎφˆB£˜¼¬F¶&Ÿ®Íìº× †!üŸM:VÛ¬ÙáD<>ÕöŽÜÑ€b›Ž‡ ˆh?T(ÖàQ 1à'±„ñ/úeàá¡årÝ÷ããy= ݺ^sôc±¢ ¶g3ùz A’e¢¹†éÉ©õx¸6ß?mè¶w¿àüa­’¢R$õ ûÀN³ çö78!ÚõÇrÓWïòó`Cá‹Åï“yÀí%#0íîý¦æ´Š1ßû‰½Ùþ¸§ÇÔêùê¾¶€à'©ô‰v-¥³ÿ]wÿEÿ³^·#öê:]èËž^î‡*'„æpt·šžœoµ®Røý)#É =o0ÞùÏ—¯H·æÑ"Aº„^¾´xÅ Õ^G#‰ B€gyæ„~ãvŸUrªÖRk&7’F¹jùeÔ7@çãcÄgƒ.fÅ>`U¨¡lE4nÄ HÄP ‚ ®€úüï;¶ûo¸^C—ú/Çk»f§×>¦M` x'tÝÌ¿;Ä~-mW›îòÛ®"ÿÎuŸNöR€ÿ´|ަÜ?™ƒ¶05}ÎãSwoÅž’»ÿ¹Hì.Ø$oû¨àïQÏȳ*‘ïŒ&µ»ŸUYÚ†õ‘95¯Iæ…ȉl²{@nM ߈ê°ëü8l+ç 纽öû§ $^¾xðÂÇ»»f°,vîÐÒX{w¶±í˱†ÛåùS޲³l¥á¨K´ZÕ¡ûOâþÈý§!}›,s¹^L&à šÑûÓ|¹Ï¨ §É˜…“> ºÜ¢$PCҊѵ”cø6\´Dj¶5 ˜leÉ’‘RZIVÔ(ÿÆ‹Ïõ·ó8>Ÿn|*“û¿»Þuß•zõh#çÐÿ±´L†ƒ–zÎζWoìVóÆ(ÁâšhÄX»E6‰Yšhºš1 g¡S*еi‚‚+'·ÿf%‚ïü%ü“íŒ|”éyDا²JêxEÖû(LÒËc„öšó{¤Ÿ`XÕ'ê™/«}L²Q‡™})ìÃO–MŸîJ¿fv·øótà0l¢)æµ±ñjFÖÕû'>Á„„³FDEP™îÊkÌ=C” ê:HØ@!q)!Ò¹ª³|¥WìÉO+¤Q8Þùž$µF¼£±7ëµÝξfPßJ*­³gxÎŽ²ûªöNËPa⤠"ñ™ó…ɺúïŸäCÊœÞPûùªÇë–н’ÖhK‘’+÷°ÿšZ®é)%ðÒ µt-pW,mÞLn@™|»ÜÔIÞï—ó5’ÂÿmvP¢’ƒ&&<³CmÔ…—nCê7®íŽK‚:mFy‚‹ê²mì:êÏV=˛༧…b€ÊT F>W½é„"æD^5[déë'³¥Í€U¾.óÔ5 +6>02QäMy/¢æ`¸Y0µ’.‹tiˆžͺ=ù·€j>¡@&ÐCz̵âRÿyÈC\×µ]sÈÆÖÆU¿…ëõü}ý§-W¥G1çEצ6]æFÂd*#Ž6a’xq"e8Ò¼¤€Ÿb+¡¡õsôý;}€×|¡’k=«±5y€$î°CT–`ÃÊ/r%ÉÖN–*ƒ_BÂ÷«ÔÂUå(É*ª´XmŸm”AŠëPÔ†péÕoUÈNÖ:ÉÒsØöÓñõÿqǹýøÅu÷‡Ÿ–~^å9ö-ùUâ’ ùƒ;ˆ,@ƒé°ÈŸqÄáTº˜üºåJR´èFg½B|·J1йÖÍ uÊ_é\÷,üÞÚd‘2s.²©WÑtÉr#,¢æ2$ª»÷k„6kó@aÅiË~»¹Øó{×óøú~[»ò¶@Pʼnàb÷Š (­#˜²™U%H.Ò¯IÇ㽩p.ÓÚÎõÚlºhü-ëÅ!@QÁSs¥8€Ô¾û@!Èkw8E¾¿Ãûűgqˆå¹Ô%ÌÂB5 %=—Æíìu‘|q;¶³ÔÒ~ÿ1ÛòW¨o•ɇ‹Š›?l£Ôׄ!ו;–P<™‚‡Ù½·z1<§@Æ1º¶2 Ðß“ÕÂ$nÜçúÃRKrÇúWþ„ÇR8×þ¨Áj­ÀÛ÷lÜÄŸëÕùQŽ?j›b_ß™`öËp.ù·=ª\ÏK%43@D?Ð~öä;ùþ#wò³»›øåÞjuQáÛ¿Pã=3K>ØÄžýÞóŸéÓ´z+÷øUuÍø{ßžÑo{KÎë½x‘fH1š½mÖ:`çRBÕ#;5§ª_Ã0% ²ÝFùDÔ»òñÏ'&DF 8DâpÁéòÀš->ªbLÒ†YMéUw‡/¯Ó‡øi{›˜)ðJYÍá–e¨´EGPÁð¥•éýNcü*hS΄ñ¬^ñÅDˆ¬ÞñÅê×~<êº1¬–oŽÁGf³\aâ%̾Oj˜t”“T@.Æe¤®X|ÝŒjàæX¥p¥kJ¯}ÞO½šê.5|œ ²™F5wBª%2gwfbò/Úaüsã½z6_SCë=ïmâ§Î $#Ï0ýÑÞ-ÁùïWéÒ¦õž© í¦¡’†f¦~‡ ~öݼÜ~ØÅa3 ÙÔFÒ‘ºdu~çÍî øÕdM†³¯h€Ê;òû¡87×ãçÒ#R&>óÁ”Àªž^ÐØÑœŒ"T@`$¹`eY[n€J@&(ϲ4ÐPy^{þðO#ƒÎc3êá4å\ì¯%â:¶÷ž×{›¹Ž1vìÙ¯ ­ ŽY9I½VUÑ6 Û›ýž0æ vC"ÿqaÏϵãîü7Ïí¡§NÜÉÝß´#b~÷4¶¼/^@°û{û½N€mù¾ön¹N]Ãç$h¸õB‰¯{ÑpðÃÉ}Dz9Å­„X¦¸Rµ S†ˆz™‡áXÞ†.ºMA}àªMÎ 4 ¦†˜/Ééí›}fñíîÆ#Ÿ¦1ö$9³!Èr^Žšr€Ë}wÄøkå1-!c>û½j>§Ä+²9»] Ê|ºÜ³”ÑjŸDµîÖq#÷ùß—ýÏó¿ÌÎ?·6Ü 'ªœLךíNàäW„Í!¿î2«…{r>ÛÖÖ?É}+|(’L0‰¥£TS%/-Ü¡ – Ý8†‚œ0(Í8NI³[0,<ÍýßwøðÒÚ‹©ÂF.×t8–¶ÿ6~ôâfþíÙ'_mÇö¾ƒû§˜´Ù ÇðÏqŸ¥§’sBj€°åמmùS ´ÝååÁôYQ¼¯)œØÛ>×âÏoô_ð;â2¿Ÿó˰Œå%ûB×^/œñû |(ëó7}õþ?·S`¤;Œ§´WAF1c/†Y#ß§]A Õ•m~õ\¼[ÑR°çÃÙ& §¹Èó˜ñ lÇ©sub#§h§³‡µ6t ’I!Ͷ.}‹·Ã9õíì1ŽÑm‰]ûСߵ‡Ÿ‡=Ù7Ÿ[¶6üú ï[ÛpàøxÔ\O®ªØʶØÆ%ãµçº¦·râÈ BÍ<Ç^´ãÖÖÍRUéw–vôoßCÆc˜þ,ˆ•×7nn‘óüLO^5Úùa7¼Y¹øYE@@È5¶D7l”ïvþ>µ6EÇ»¸‰Û^‘ÀçV⵫m ¼CIÍ;fù#¨¿±E܈=GåWðq_“ÄtäoÜÑÇ»µãžÝ5ÊiìáüqÍ¡óâ±"!Þ~S°ùŒ¾ë–¸àóò_}³XœÏìoîàxí˜ÇËóïÇ£­|cM×~)‡©æáTÌAÏú·Ì¯ðk#åKÓNˆìºmý/‚ÎÚ‘ž½¦ƒrÒm ®P_¸]ßÝ=xio]^·<ŸO½¦Ö2õ¡Êû¯é7?,àãë‰m»:2Í9nu ~7èºléØcéh··6’ÇH}æÑÅÖoOÆORñÕú]rðDâ´ÏÇÞ±1(gëÆ¶„™Ë³œâƒÍDqC+cæºÀо®Ógq `äSÔÎÍ-Ó_mŠ˜¢z|û³O¿Qòw¡-gj{lvíÙå2µò’vÜMGǹn!»öV+m£¬O{â·{/MEF¥ï-®Ÿæaªó«ŠânëÎðú¬²ï® ¼¾=p+~åXK‡8ÄŒ­4ôG\_~N³¦WÆd‡|ùg„é ³ƒ~’oH#¿U¹\öÿmKì£ÏK1篗¼²â‚”‰|6ÚpÌó}OðewÞqÒù·òIC åÒ^T›ô×6VhƒÆ`©³ÇImKêQ DiLŠ´‡„v{“âl—ì§Ï ø óMØž(ŽO*Âxo;Œ< ÒÝ]©¼üÐÍä5Üníñ^ìù<ËöòøÃâ8VÌ"ZÕc6蹴ሎ‹dsºb.¾!§›O¥Ã.×§‚¶§@nÜ]¤"Š%Iù8F¥˜ëºþ i m}ò]#>tô½u›¶^ª ñ-p2!t yçÆö ؼÛFᛸ˜ ÆÎ,ß«Ý Y}ó’,ácu]=;aˆÕù¶à@²Æ@oâC€Îʸ<75ŒgSjxŒ›_ ™ÔUž&ÍäjK™œ¾@?ߦhi$7Éê^~qœl›ŽV™õ™jýC–kž9G ÊR˜:²óðAºW÷CÔT ÇV)¹à˜[%¹£B›˜rx_œWklììr¼ïáXˆi±6–‘öw¨@—•®Å˜š(]RŽ"D‹8 Áø~È5¢¿!*€²¼\ 0C°×³D_z)è)‘SUˆ ß÷|'÷Æ O"ý^rj ”Q0~4ðÏâ1"aÀKEAX¡Fåuv¶¤²cnÒlŠÈ¼â¡"Œ@$[Êf 'ÐJa%(/x`ÍìÆhcÄOb·çʘ•zLÛ¸ A#ˆ¡‰—%vøF¤¡[zdÓHe¬¹‚L6b&H⃷éM¥Ô•zP€t˜kRþ;­³vúäR·f)«UOc Q‹êsjÒ 0²ï…ÅM¼ýp‡7ßT×î~Œ<@í€ÞcÂP‘š‚Œ‘á¿÷óþ}Oó9øvx_KÌ gÅÕ^¯8Jhr•-AA[¨­°n àñŒ/ÂÁ‹¼ÜÝbKXÝAÝ›ìÐó¸^ò{£D•ƒQD)aJ_œ Ç›î)¶½ÁáéÒ"”<Ÿkã~'ºá²(ŸýÚèô] ²AoQNRV2vêƒÐ÷ñ´6C/°b‘¯UÆKuºßyÉ[ ˜¿M»ËQPN½Xú€¥ ”©¼9ÂÕ³}»¨º[AC]éu~eB~+¨«­(\ç$À)­É•U/ÜÛß«!e‘ª¡Ë/Gmô@ =ÞšR¥ Dg¶xºNpyKêµMHYqM¶„UU¨×usz+,3?!~šªŠK$M”2kyd§ ÚZ00Iárøw'ªžáÁ¸—c2…¤úú3¹-jý‹³"èÞÙEâYÒý°E <›FJ˜(nÌZ¯ýÃYÎÔÚ…Þ¹k¾6XÄ2×+‹ÈmGW>ÞU—ˆñŒðpò2»gcüÖüœ}Çyà;nO²ø$sW{‰Õ¹y3ð÷%ݱí $=ÛYÛ³ÿµù›)¯†õ6ˆ¼bxÇÇ,Áô>\3°AoS"K\‰`_œé¯XzHâÆžñó`jé×¢Yt/ïêE;¸¨.(€û¯ƒB¨égЉ;î+Ȫð(sP1DTGš×jzÊ×îkJo¹[ĨÙÒj©â GÊ^@IÏ\¨P!Nkƒë·_:'Íx?X»Ôr,Ç«ÑýÕHU@¨·‡ Ü«›¹vï&×် à¯É>2 ­Æà?ã_¬¦žx‡›9éT 8I’¹ å÷S$Ö®¹~ÓGQmqÙÞµûT/­aíÈÊ|(#þVïÐ|îóõ &èΈ³†wd»àÿ=áFý¬=‚AX åë¤áâþŸ÷=Ä’@;xÈUAŒ²L€ŠÁ,fŠŠE,‰4R‰4ƒa !! ñúVÝ›¼üîí’ÒÎÄÝvÛÅ·ñ™Ã}*—Ø–q½£]£ÄZÓ\8´·½¤í)Éã\¼}YwîX0hX>Óâî(z·¡ÈŽ<#ȃH2HR™|o±-üúcåìÿ'¡â·œÄãÛ„ÖC´Œ Qàp°¦48E†Œ$Q,>áªÉ‚4OÝkAû}òª:ÓϹ,m¿ 7óëX×ʺÃŽ·Xã- ½^ªXÙ·è}‡ø‡bµ‹ñD4έÀ×Çac.ª‰=Û:º{³Íûo+ðþ_ÀÐù˜÷)Ã#×X´egëtÆtÿÇöáæ~Rþ_(ÏZ]EÔ„€aBD:,«æËÍ¢Õ¹:ÿźûêý¿¨êü7´Ê÷0ø™]Ôoú, 8A»^çhÈxÑ ÷ï£uØàröc±ÓÀNYè£c÷¼¬3üùûŽC­ýtÛlÁ,Kï=Oö®¦•ùø4C¤DÞ/ãxQ‹U U!©äàå,¹‚cWy¿î¯”UÝ@‡dàðjDd><>~å U-"­âj|ë.ÃÏ{‘¥ÏnY«Š¡F¨+RúßÑ¿Þäg”¡A¹Ä’…Ïüt-0¢5_bÖç—è]>Qôþ= §ÏJEkÓ¤XhzlMbñçÞ…—æþ$û½ÎŽñé×£Yùý¡³±‘8F‰(1PD@Dõ9ì8ûPx ,­nÃk—clûù‚U\Wv kJ(í¶AÛüNϱ<â*-À›Ë~[ÀI`AA™ìiA„³zŽ¢bÙrÿë<¹’ü©b’e;¨ê÷ûƒ1€y‰v¢ùyÄApÖŸn Fq|ˆ¶÷^®¥Ùýû*}E?ØýÙ|Ó÷­ìªø<ÿ2ïûQVÖÖGžÍMâx¨?uFiš¡~»(@½×_¥kãµ-ع+(€*I òÔ“Ó7ñÿ¾q^@Hž¨ªé¸…aÛÛÙj3üâW«okÈw.['À|1B<’·záYK& FP‚ E Œ ”Û%‡—Wè}nô׬נ´½Çê\=&kYc»ñ/ü¾&z2`Ü•-”º(²ÇÑ¡B@ÐŽ!e.ù…ús\ÞÊã‚«˜»ÈÃôcÛŸŸóÛòÍ໌|ÿ[µÞ6:›ßÜhî©­•ö~|¶ËÀïx޾¥#=]Š’gòóÐX½Ëv !·ÿÀ‹–jÃW½ÝÞî5 +õ\`†ßdftÊ£cýF¶;¥™¡iâÐB,›}Œ `IÀA+šÝ=jÞˆ¥žTõŒµ,(„V0^š#ðPPý®£º³zìŸuúʨ4:€5OU²¯øø(8¯ec«ÐÀÉíú5 Ý5‚ó®Ì^© êr=ïKµæúÐ;œ?õú÷ -éç}ÊþÕ–@¹T¨7ÝRïð=Äï|¶ôþ_šŸ¥ûu@ÔB A—%0Rˆ{y >6ÿä=_/‘«;z”ãòÑPH RòD¡ZP‚I&~ØWÙåož÷CmûèwoÙØ`:˗ݶî=ËNþèÎçÐé66O³ ìòüÎmﻟ®ã5vÐ÷^ǹ£÷ü5·ù0’€óx—˜*üÜÍöº»#ïõ›¶C‚HsÞEýÎ3ëùŒÿZÉãþ¯(OÛìa  E²Ô5ŽŽ Uúʃ'Ë2[:-[šÅro¾åUÀép»®Bå"dž¿ãn3þWÃ/‹GÅ’LÜŒ'ÛÞó¦"«ˆà+þ´Tuœº $îZÔhú~-õÀ ¤¸+;kËs%ΠŠ"(Q­Q oX·àŸî6žWãqq7ì3¿…Š;ŸÊ[ƒ¾Œ¯ÑDw†HŸò…‚€€á[È‚ë^úÊ•ÿ×߯±ºrt¬Qø » @õÑAERCf€ ¹OÀõ8ï0Ǫåó__³5Õ&¬²/?çëñåø¹£ëúNS~5@ó°ô±~ôP€Q‰wâ‚™@‰xªÂ×KeLÏ”„x»'¯$¼<Ãåq²£k㣠Й²‰HˆECH< ÉwÔaÑ? †Dø'àü®·‰i”¶ê<œv)ïϾKá% B°6çèàÀI‘d˜ƒ–! Dˆ ¥~ûö‚ý šñ¼0s<ï¹ÿ:¬BêDê=íA7ÒÀð§}[z½ã( ¼Åßs@={¡¡½ñû•tûquèݱßìqßÊØSE›×ó©Ê{îàaA:þ¨?«Þ§§­æ#±rJ¡vÔ @ë!¸Ä~)K³Õ‹jhåÐe9^1@ÆðW-ç‹ÈkeK #~æîwœµ‘§×_øÇ¿ù8>+{†Jð`¢éß­Gã´jy*ôFb<ŒŒ¿ „FÞ3`8´Ì¿ûvÎ#²õ¸66¦½ IýÞ*Ùá­ñanÂî}…ÁG¢!6ˆ *© ”(BP€ABte%ÁÒ^'IâãÛlé'ó¨ËLþl,/dé»Êõk“/\áóxns‹Ó~<D:û!“ÿ{[¯xú~l´gý·E"H0„¹¨gáªT°(äJ*È(˳ƒ‘€˜Þ¸eóMÁñFêô(uZŒ'­À=GÌÔ u\›¿£2ëÈ¿üÜh44œ3?i×ð<Æ޳ߺÍÓ÷b¬¤pÓ(Ûv˜Hf vä{ûÿî‡å[ø¥¾||”QTB’#àÞaÿk(31 üâñXå¡Ä²è;}K÷Bq ÛºS€ªˆµB'ÄNÎêU†Ã1Å%ûݾîUíˆ@aŽˆ♑°ñÝ|ÀRÆ," äJ ¯éw+¶=¾Aýõöœç}ž;ر¼é´¶»ß’鲨S®×à|¹mO¯$we2]~+¶°è=>û×Oþs?ËÔ1•äzÛßßÔEÜñ[Þg¢ÓõÝ¡zý4¹]gñˆÏæ%|W{[cõï0Ý×?´Ãð—µØÎõ>¿Gžû1TÉ$ä•N ®3QÙ´(" ÈP‹2£†,M”›=rŽkäWu„*J^G—k9ƒu(ÂPó>=³59,£íØ_/7ð{øÿzð»ïÜíÿÓöà|L/'âÒÙë3¿§ÓÂẞs¤ð0NKmñî-@œ‡˜û—=¢wpRȸ‚„+Ö'ÛõUëÍ~Ÿôn¿¤ýÑ|4e=¯¡qw#§°ÜóJ"”B@@—Ò”JMºt Ø ±H²ÓnÞDŽ/säo?ÅÓ^ûnŸÎ×fnð÷ó¶É­÷Ž»P×Ý*ïUIe;èùí¥)¸Žë1ð&¿gô8|5!óöíÕCçþUövP°²®í± "F¥m’¬ÿ³öß±öøs¿…²ÌÃùà/ÁÑõMüCZ^y((RSŒ“8µ2üžW?r÷ù†GÏ»tÔÀÄÊF‚¾¨Ô£×æ´Û[”“ØCbôV`CR1½¾ÐªóËQ;°‘}òîµ¹%¢+˜x’·-Ð(RÆ2‹P‘]”D 9ó¶Ï§Ó^m"¶ŠP›M” 4ð6r_¬ó+ó?"š>{î6Šü”ÆÞAynÓFÛ:åmŠí)$µÁ.,¶,Z4s·Ôò^§°\¢Æó{öFæ1VûvtB§Ãq±HÎKÅÀ>{hº.8WQQuÑ#¿`¼þOóÙVï»zºÞÑV©G]ûž›êƒUÞ+—sSÐo¼\:ÝOð,ÒûÛGYr×bÌñ½×Qð|ûÖ{Ê|¿ŽúÏç|«J&Ø~º,nöÞC‘ó=λõü‡­²gð¼Î_@ƒ<ðÙfªbìX™‚èÎûçÐÆÖ/ïz ò¥à“æVÙàÅËÓf¸l»§Ocì÷F¿Ü¹u¾W.g¢ˆîe´ÖßWçsI½†’µ¿¡™ã6g!ÖÛÀ2Û„SåušÔü»ϧ¤7™ò+üùݺΨ”ýR'=¨é5›ðcc¼ø@BHÊMðŠˆêS{ÝJ°$èÂ’2éÏ8ŸÅ~Þ¨2l†æBí6zOg:¥úÓû§f°ã&O´Jy<âTGáÑ!Os‚+ÛÅi©Ðh»¼ró¶oŽÖ C«ßx¿ Î7Än­ùsRèl|fkàRf÷ÅÖ{r.tÎÐxž —-ëxqAðDÏ}²°öR?ÆÐÅüª* &&¶±ˆ $Û-ejÕí¦͹ëó†Ö@}ö|Þ©ã Ý§ßRB.È¿x¶`5 ¯¾Éˆ»üyDj!AxÀiëž)Áp=ª+á*c19æùF,>óùÓAŠ`ýTäKlŒ.‚3,ys÷ Q†¢|ˆd›'š#8küÓ{¬¼ÊJ"aGÜëÙÀÝëäa¬~1V*C(ýõm$ÎQÕTÅR„}Œ”Q[5@‚—*N¸Ó_Y0—â”BËt™Na“ÐqÛ,hϵeà’±„³ø*žæ÷ȼÉr^¿!¬ˆY¦já¼9hh[yo|»Ýîx;ÊplloêYÝÈ»«å~§?¿Ý5½š>€5Ý|ª#Ÿ×•>Ÿvªã<ב`kW•Ó#I¯jWÜ&Á¶NQÒ¨] #9Ê×ó™(ß;‚¹tœ<éCÂî™ÁÌ Õ,”,ƒP üîìR!ŒTV«C®­9|ª]Ê ¬Õ=³X®äïU—ïO™½Í¶“g¯³ñríÿ žÉÞtJ欑’0Û?2`ú£â.F¹Ë„,»ÃYú6ƒÁö/ݽ߂ìû¯$Òk8\[4…X»ÚpõÀí<´Ï;ÛÏÖoÜNºêÞpoN#XÑ3¿qu©„þ@óé/þä'¤‰ñâìâ¾úÔý°7B ÉEË'ŇqЃtC϶ON!ÊuðÀ¾¢Éö?€Ã’{9Ïô7±,CJê¿…ôè°ŸÙð¶I­A¹e ®Â’ª"­5óW\ܾ¸ûÞMÚ‰Äág­ûU áYV2Z0)|P3lR©h© Ž\ÞÍðϯc ”D¤ã•VÆÃ$Æ6Ï2æAþ%tÓkF¦ÂìÕÐŒ{¤w¹¶ m±&²„a»^.Òò]xw9Q§`mò\•‰ˆHth--™VF˜¾/†²J'DVCCê$ûN£OØûºúÎ? óÙ's÷7—7öè§c>ñüŽñâ3@|êÇIXQºyÜÊŠ÷³ÐmªË£Êë?çõZëiO9p±!©Ïýê7ÀãŽIB«Fh¸@´åªë^û«×v Iç^Úç7€_{U±¢$pp`f¦ ,bÄÂØ†Ä?ÈÊTè=K7G! E=›¨ÝºXÝ–Pµ”Uz«Æ!H*œí.î¡D#WÃB"¯ø(w• ?›k?›oŸÎûÏ:µ¹åÏ“°`6>ß½é6Ià$õ[äáÑw2vÖÜ"‚q ©!ûŸ`¦)Šb„Gˆ×ÛL6™×?‚ÓËÓ‚wi;íM×ÞŒeu²'š,º¤¸a2¢9LteO±Ù¬íÈôxº¡ÅÁæJ°ÊJ#¿!\\׈Û §”ð}8ÖÞX¢IR‘äÕ5ˆbMþ¨³Øôœ-ŒÝe- NèzO¸ê&µàwk}í_wß[ºç ß‘ns_¥5ΘMá @RJAâm6}±^íg©íPÜœ3Úgà“¥ò2ÐÑ?úŸúôÙù›!Ø‚@_{\.B“o‚ÛÍ7n›†±sšé[W*5¯%o%®UéW*º0—®Gýìë$ñ¼eÜëßr2GžJóHw¸äb×8ÊÇä±F¢m¨‹,¡/3—vkbA`{S¨Ûz¯è>ôl*Ä«[½¶ÇN1k{ôºÙàõ¬ÃjfL™Õvwd¸Ýt\ÛŽ4Íri™ *sˆ1K³ÞÐb‹ƒ—¡¥w‹ü âø ²BÄC[϶D ³áÅE„¨ÜD- ˆô``sgÖñ»ÞâÒ¢Á`tëZz,çÿÂÙ‚‚ž»(SLðÚÑ5ó×bä÷~_[[Tž¶~þodÆÙømüúúÅíüGôÙüQ0æ±ùn å*€=´OuÁã³õ§_8HòSñGú å¾Š Cg7æÀ¤v1¨·ÍÕ%%",H°¼eçWSdséµÄEë…Adå$±ÅY‘ºLO7B¹ß{4ב°c$öì¨yl_`a¡¢•Å~ Éyúõ¬(د&ȯç^ÇQ»° ‘ô!Qý)ý^¸WÞ£6ð΋¹èw¶Žæ÷Ø+JT”Ã÷˜ÿž[f¦NC}¢Ê‡™¦ìÞd=?úÁÌcÙ¢ëjYã˜î3ݾ†Gˆú )Îÿå¢Ôõ=NyÞµÉGÞSUŽý=ÿÝùL!ä÷}ÿ¼wSŠ® ë»eguüÕé-W~òà¾ÇZÆóp)Ö|,»˜5¿CTéFA$$:L)^jFeUq5á­WÕ5Cßf`ßM®Ó«æy7Bb<^Í­iÙÊ@Ý´ö8ÄS½y2Ъ3~ÑpIÑ1¦9gœ|tΪ}âc†‘RZÛç2ƒ® çßW ý?MÿW]”è°€†”a`5gC,Ò­l¥ t3Gág–Y'¿ªUÆ3åÔ¥`¯IŽÛˆåšTbø”å9ÔŸÕj:ê¨cв«ÎÑé`Ùú¶¼÷ê]Á«PëìÂÜhcM@§¼…Å£¯×Ï3¥4Kkõ=¿4ö™­7»»b{¦ç$3.¼ Æ;YuiÚàfšÕrÎRp(íñ“7f§«+Fl>ÇdÓý¶û´ßÓ~4ù9ÄyØÿíÅ×Pà©øÐÌäçgŽºƒ´€óÌŽõ†i«®ö¡= aÃ\ìnð*²›ì GíÛþùË€×L¯Fª >ÅûW”CÐÿÇw+‘‘=›‡³Ùk¸*XéV‡ˆ "„jQ“Ù‘Z”$…—E PwÜäñL“à¦Ðú|ýö~kÙ¥å´RÎÓjß6  jø¹?BcÍe 1"E=R§bMÊ`T‡QØèG¶d®Æ;Ze¦ÿSÍÜ"$Ϲ—Ë! h† ¹(b ª WœSZßdo­m°xgŒÏRyGå\˜ÞÌ'ç„z©x3 Uueˆ ­Žx*¬¥€³P5R'$-ÛCoƽA&ˆÆ…¤7i†°ªjÃ×ÅÊ6e'óÃwXýÒŒRmö¸x| 7$^“²kårägYÕu lKIO쨋kþ¤Œ<¿XúÝ{{éF¬6eõá-ðÉÿî¨p‚›þž6Š£Æ+?øæœ¤´Ž¿vQ*O¹!÷úffU`PÆ>;}Í\Gñ×^e<â@ÜÈŠ5 HœÆ*¨(ùLîåL0ŽXíj¬*rû{FåsW>GåÒqYY{±vꦇçÔ {ø‡é_¯Ù¿æ&§y¦ Jv-/˜·äi€”´¸›3Ô‹J™yL•šƒV,A|¶îÄK—-rœ2\¬¡˜HÇ:ÄÙá',Úà±7‘" #tµªg6s.D²½äá¹K!žmÑTþÈØÄƒà¾aÍ·ÍuóÑÀ6†a'h¬{bNÛ‚©fQu&³$íL!ÙÂ" tD¦ÀNf`‹6f™@£òf<Ñ8·34´B;nÙ¼y!"x8=Ã0ei{@€Pž 2C2În`¼’C$ºá´5§¶£§-ãËfjÔëÚªë%lÓÓÄ ÝT 6ÌKÍj‰"ø©WOTª\¬°ÄÖ°¥¬9ÄV‡NI€ÉýÄ2AIø}?*×cg4\²Æ&ý?ŽegL L1JesÐWRP³Þ¤ðRÂaHêÓú–s×v¢ùþ]¼Q]Ûµ;¹¢-·Û«$Ÿ²‰Âna P:ì>"`­ˆ(/eˆ™cï7`ó=¾²éPÃÿ´ óÖˆ^u}uÃîÙ­ùŸ¿ôqÍ Ùž6º¬5ÔÉÚà&q½0E+|ÿ“þ Š(×í×GÖ'_H‹{ûÛ˜µ°E‡q‡Æð£™;ôäRÞu²È§¬^j¬…yû•$¼âO®X‚€A#ûZ(€ýó-ƒ£‹¤“ñ¿÷«Áãàb”7IøúªSˆ†(;(çDxH‰ö椌C÷k *ƒ>Æd¿ñ÷ v?†Ü@Ý"¿³z ÷ð~|wS>{¾†›AõþŸo=çg}5pÇÝÓÖÝIïª3~ù0žÖtpN&<&Jª&Â~èŸK’À² Qጔ&>åØÎJàöð<Ó‡# ‰ÀäN~µ6àbí×WË🣮‹Ä¯PcÉÈ`RCÑð*§Ìî–xkÉ©«ÖªŠ¶ƒ8hÄå;©¡!~îèu—¥£ÔëÓ6!æ¥BE2¼”<Þ`¶â‹ëÀú7 :יƳ ELȆZê¸De;8w“‰&¤_ß"*°˜Æ&¿w'À„þ‚$D¬˜ÛÒ„ÅìGÚýÂ;®> ¹ÐeS#œ"ìP­kxˆ Ï­¢p¾ü’ÐÀ¥)^ë¿ïÏÞ×>ŸýÚ¥{c#4RB "úGÒG @ÂStý ™%˜*@'oª•ü^9…T}5ÔQˆ´Ó»O°½™JŒ…Ÿ®b çnó»¼G*'Þ‚œ¯Õ£KÚR8g GÅ·¼ø^SO÷ãÈO/Špy¶ö†fˆïðó^;KMÖYIÈGBŒ­™ó<2¹™ ÈYwLê„¢e§ÞKÊ 5¡ ”ÿ‚z6| }KeÜIQ4€eI2gºrüg9ƒéÇAúÔÜ'ŽÂs wÃ$4%,%ä£ÞRyÎZ”2c¥<ßÒ¯=®(™Æçè\}é±§.DlH× *9·À¡¢{m$Ñå?qJú 1äI?ÇØ¿iú*Õ$„6^É„mlo? ü<5å Yáy^#‚ª¼•Àª½³,LÃtƒáÿ`º_m#¹1Ÿ¯©lÓf—_^—‰.ºýNk@."ÔÞ3”ÛåÝ |è:Í]^íôIùïØ¥éSsÓëÍ’ô²œÙóIC€ú9÷žî^¹¨¤S¬b܈| ž=Üç.ûšTムï`?N'q—Aù#âbd¤2}zNÊ=DÈëMV´-q´ªÙºïê’˜·Ëukó_î~{—~°ÁV™â’/ôFN7÷²wàj&|•'(*Ž•BÀXŒbE@^ûB £€Êx5þjü”¶b‰åøÑ"Cha®þm¾…ªˆ±MæÝ1±Ž}3 põmÔ´1_ÃhÃþø´˜ÏÕ{ˆèùœjæ@]½AâÌ9Ö¥f¶Æø4vØÓiŒ£ `ã9UäDlcÀ¢’@·1,U¦Û­°b®´®EnR0Æ™-#y3ãElZ²(ÀíA¿\\Û¨$69œ$£GìNuØqàÉ6rí p¡sŸ7ûtC_ìrZÏgw 6Ñu¼]_$Å %C­äÃŒðµ™/éBrSÚö•£veŒéQsbij¡íàa4%ÆqBzšp‡G*ÊftÝxñµþ°5"^œÈ}ò΢¬̧«@ÈCñ¿‘wÏÕ³ÄzØÉ‰÷ĨA7·˜•ä4ö—žÔJ©®e•xX°,èBúY•ðTcÊ~Còe¤Ú´)Ôvk(– XQ-êÑPbJBs…=rù“êÇ”)AÌŸ›¨x*Ÿ.¾y©9ýøm¨ûn‡Ý¤¶¡BOÿ Ðaô©ÿjxnŸÒNTu<å>×¹ñv<œËî(Ý33¨–£{›ìBÐ$ïç¾<'VÊ9î»WÇ»3CõÓô_- ü͆Öa19)ÃÕ2p‡4BÜ)v„Ÿ>«F\_œ‚j£þñê»*ûž¤&’´´"¬B»Akñ<¦¯òö^Ì_¾x=¾( ÔyyO«ÄÝ5âñý2M ïUVÝM7™Žä”(šÒE`ŠÕÊnÁ¹ ¶FÍ(saYäÈÏ‚,')œpI'Q¾È53õÖ¼ÔšXyóŸ?òù.ð4lÓ{YZsw9œ÷Õç×},¼š2×靯÷3¦ª•2,¯âhvzyøn©³…Ú"¼*˜ íNT3<â„:ÓçzøÁ#A ÌÚ­Ûw`á˜â<‚x÷a»WA±³Û}¡»Vr&Û+V¨Ù#…/—kj6 Ç2R›{ÀÛî—íä·'W–·6ÞÕ*–EE;ª“6b]UËO°÷ǧ¯«Éâ¶5¼ˆþ£íf|ιæ>ûÜì~Ý‚m‘³h8E×h¶Ú{)"ö÷¤¡ˆ+ØML¤)‘A|ƒB–ÃéÿÔôÛv@Å)(øóìn™´Žy­"ÀÙF@øIµÌ¤!£q(O^+?HÒÇO kåª É IŽrñ ¹‡Ú^„Öœ4‰Vòf+ÔCBµÎcÐ0j&¨¤øTÓ©ª 6¥Ö= Lú×ÚËð qkº÷ëYíkmh¹”­­KHPŒÊ }Ù•¦¦·¯r‘8îlP4dlKåÞCèõ ²±‡@¨OáBaáØ¯¢ LŒZ5xµÐ0Õ#ómÓ½SyPÞBÖú%žt—Ê(ÂTŠþJ?>'%©c¾”â Ž²xYEiòS¿7$¢„¥y|Ò!:‚¦»öCÌ8bÅõ×@¢½là vjêã¹–¶YE&³ß‡åü ºŸ -_µbè™ìØCl0¤ØqgG ËAEBk©“?óE€ä1H$w ²¥ŠØZˆ¢Ä—³K ÑØv?"¡ø¬8Ÿ—Od“f•å3ñ›ûjÕ‡a' c‹¹.; gŽ;4¹åšéͬ=`·øìöò>ÇJö‘íýæâòNº[iñÓö™~f§¾Mé?]'”Éólše6š»«JžÖ Ñ»Ly's‘œ~X|LW>^ò˜AÊãj±”Ñwµob“ÂÞQñàõW€o:ÈByxù˜h@ØÌóñrËg38LªŠÎìL˜´ƒ+mŸiûžüùxðU²lI³}Ý'3 8[Z¤c‡Ë—wQÀ™8b˜òDQëì4ÁB~ErCŽ«mP#÷߀L«L«™oìnº TŠ UDDb ´Ò«Š)‰wÉrз´åA^›ÁÃkõÆÑíÙÕTÕÕ+Ù¼#leuÖ0hcÚA²lGF¢d&ùh ±  @ ™¥tUG4¤L’ÎàŠ’¬‰0°€çÞZ*B6ÓìÔU:åeŒ®áe™Ô)ó»Ei‚›§ÍçF¨Õ¹\¢"k›šó¸i¦]æ³M7YU´Û0Q˜ðÚcm†œyM¡¸ÈM©©¦ÇgFƒO]z¼º÷½^xô“pDD=úòñë×zkÒ0BP÷ÕÉŸ(´%FÜ­Ë'5sxø6ÝæìQ’¯}É-uÜw^ï{¼cǺ î³ÈŠF QEUŠwï4Ãá×—w$¡“œ›Èo&Ì#“"\A§»€ÇÕ£k¥k•؈*¥0ÏèP šA†vgf”1¬•ŒÑ7ª h“„(ÙŽ7³ƒ¨µï®k÷6õïÕx›»¡ãw,M"œ |F“^”À縅V@àØ©?ág,´¥‰4¢·VA.øÌ§Š¨'“\Þök;ßêìÃ0þ~â™®*î5Hzƒ2zÁ3køµ¥ðïs8–ôú΋2.‡eöÔL‚¿Å%‘>(^zwÌïûšnü_".(ʘa…‡\†»ÄèKŸR†/þ‘ˆv2@äˆ7+MÈħž2†µðíßJô™wÛ¾ˆË´j™¨Û¯).£læ€ SwN*Q«XIæ(ëZ¥ŸqtH¹ 4Äfì%Gb WYÔV[¶b jk SãA–q.gÌåßiôæÙlÓ˶7zÓj<ÛÙˆ?ØOÁ=l+û+9¶¤ùã–쉧Ýœè˰¾ü*b¶dÃÖÙ =ÝÅËÒ.Ë÷rYâ¡¶» 7@ÓAZÚ¢,¨ Ü½7ÿQ>sBåˆR€]Ú¦Üý‡å>Œ3P]|‘éb±X£?òbÌ$ü°=oÛ2xšç¸ÙHLX°>‘¼š¬è&ÜoØH‰#æÚÞa’ç|e›ëšÅåÆ4ñêÙð“9mG‹q°…Ô"áÁI‰0¡£ o¶ÖívUJ£ÍbãË9<_¶ÿ=0Ó07ósš@F/"TwBqÉ>¯hU#h9 ® Q‹Šd»†$`>GPÒš\þ¾m파pÁ‘±³¶ ’àÆ¬.e‘XX¸j"Smf›kk.ù¶ÈØp— f÷_³¹çhÒß*Ýñ3†ŒeNÜÂI8Ê 'X6±À…$„Y½Ö¥ `Œ‰$`·`·àZœ/†’_°Á¿¯¹4?¯ù—x«Ëª~¸{©üLýã ?Cß"5'´p«±ÆÈÖ/ ØÝóg0–:îïÐìØÎ现Æ@Ȱï7ö\è`túH¬ ŠèV€ë=7f·ž= xñËXf|LŽ©Ìö«Š´¡Œï‰|s‹öœv|ÊÙ–¥¬,YÔ ´IùŒnß“]J!²¨‚sÒ´Ä3tá‹!&ä.ão•ívæDn`1êÉë-ÚÔ2ï×H÷™dàØÖ3&sdB·pô蘻VHäÈ~?YC®¦Ä;EÃ?8ý6xîx‘Ó.)Ü+‡\ï;ã¢MžÚx¾*ŠÚ‰æâÙ± {‚HM"Ú"¼¥"ˆ`Çe[`[fÉšº,ñæYùìÁ¤Û“nb i4òC:Twx)büEnŸ2+!è¾/¾¡˜W fitw Uš—Ž}x^²EûÀÃ.ÊìƒôpÜÎ…Ú6 Ár¦Cc°Ðçʈ íg:¶Ïµ­l˜S#¶+Îhew¯zH'‹D;­3j#r(£pCy` ˜øÃÎ3ÔÄ%ùdLì슱È6NðþsÉÏMon~@›&‡ÄÜ¥7”™R2!™þJë™CëkQ:kðåõ(xjÞòrÎwãÝM c²/vÎÍ3˶Ž·k¼'-r¢WæƒÐÿïYz&Óªðá!ˆC¤­‚x§IЫÊÒVuXëÙçu؉_K»30òovçÅä_à{Ê$LKÐôrkö?†dËÕæáªLôÞ±Rb•.– È~aðeÔBZâ †z½YT;D1Å—Ñl¿¶˜¯¡G'¯£ÇGªÑ»'P°—¿hL`.·"`23†¶wvrv´&N:jpcŠQL9ŒFƒŸ=,ê—ÀÜîÁ.ŒßOÉùPè?×=^=N6tRR7‚I YÌý]Ì‹Z:jàÞI»n•µ Yu£ªqßÌÃu±ßÚèÍ´à¤ù>Òà_·rÿ¦ø-~ ä]++ž­ÓX*Î=bx›¦¬ßãåà§èòY ¨×Üô-cBŠ‹Ôâuc·|?HHC£Lٰϼ¯‘ÌH?‚òüjø ÉèøuF(‡Ä%ª®fWg3ðêfx'[Ù]%ôžæ¡áx}ЬîÞ ˆœxÜøRÁU¬k‡Â?'tîò÷õq™£"ÀN:g|ûjnn¼ G®Ô»Žâ³¹áq8d”™‹.9„r« 圂(˜°&ÐÍ" ,ãU°y¶U ˜6*Ü•]5€oæÎÿ‹Åµ×L× 8÷ðûhG[·PÈGÔjE$ÌxãÑÁñb#wÈS¼x¸ ÄóŽHäHYТM57’§†²%¦òf.BÁiœZäÂñƒoX­X¡3$Q²(„mDÁV:*Öõ5ÇE}¿Î×þ ÛÂÓ磢÷ÜŠ„Æ’úgØv´)ŸjÕ…vQÊâèz_—ªƒÆùªÐA'ð3ã6uô7˜ÆËìKÈOí &¥NØ{Ž¥åðÒN…±:,m8`ÛVP‰þ€;ÿáЂ$h)6W/\öžy¬^9® âý~½N Ž*ìÊT»Ø»Nh`E‚,u¨hšC UвšpPó&uešúÍÐñ•™é8r'‹»NpQb°À޲ ™¤å5aHÕT(Ò¡h(†‰”8LÐ}NvZ#™ÝZ=þ8öÉ¿Ói.tçs2¶íâáÄê †¦ÓB‘6elsí¡¥B:ʇœÝÅÛ²‡17Ðv êcÛâzj”J®M!•í¶z!a]ÖÅ¿S š3iÙÌ®œb¼_!ú&¸÷Ù»`FÈÙ¶ðlÜàôÌ6\‹Æ!I¸ê•‰6#,lñ•Ú½6ŽÄ‘Ciš«/, 'hç1v, :RÄh¯ 戄nX8bïØ¿ÐzG£—”sbE6ÈᬠC³²!·ÃC«–Œ@äÅo#éåŸgmm Q´²éJµ¬s7y)Ý„6š‚5Y§ìÞÍæÚDño†!ÎX]k­1·¥&uÞOÕ©-–LE#Üd¸ò/I$¢ü4D¥(S3ÕÄÎC W,ï$CÅÞI{'±`Ð]<+ëGÀŸÀCv®ûàÌ!O UI°Þ^!ð÷{µÝK¶¥ÜvZ£Ò„_ àù¥n×w s†.Ðø÷¬qÕtË7¬›í«›ð˨ÃÕÕÈn¸œ×#m>O¸¡É7‚HÂà•5¬>©šñ'‘`§G‰)*„&ç¡Dä¹*Z0šU,Qh™]%¥hú˜§XÒgM%§Ú·€}+>=½kƒCg‡G NW ¤ñ¹v‡¢ìâI~gœ:—syÞÏ7?2Ô㌎ž?ˆ×£g¶q"÷EýeƒÓˆ»‹èsfÔnm‘2l‘y ÝÐvË¥¼VxbA¹ÃÖYh¨MˆÊÎ8¨c¼Ô@tÑAã ·‡½M-áë‹PwZÎ1qrÔašÕÐËG‡SÍËË=>o¹pœ ÜËöÄJ"R uÔ¼î35«àã+;å 무Þ/«Í0Ÿ-q D…‰à^)Î`§Xã1¤Áˆ&òÜDõ\ã…¨êKêì ã†o!–{ñq;¹xŽ\QkìÑÎEÞ ±f µ¦g‰•]«:íyОË61!M±󪡋«q‡f£Rѧ¦7^lÜs„a •:˜fß,F"¡ŒF¶ÛÉôû’dLÊ÷·Í¾«1³ö!ivCd‹Í6º¤}3Go‰¡¶ÍvdЄ÷õ°µÚyrã 'M|¾^,^MK6=«ˆËJUûóÉéD“óTnƒö{H¦\hvçöÃÛÛâ—ÔÐ0° ˆl¼ Ž«+"jçá…Oƒè)ÂêC¡Ÿ>åiB1ˆ¸’2øé ƒ 'Ž:(Dïíl¨Alb›™$mÅ|¿ ˆ#¶r¾6F¨E¾B€âúP-õøàzÿ}y¤ë°Ù]ŸÎª—¤êµˆ¤}v«\us1|®mú²Šà~õ¼üÌ|t>œ Šû‰ðæYÈŽTäêßþ;»Ú"Š!¡3þÍçžA  .*¥ðL•1ÉÝ"XÏ®“¯"×½5憇Z>ÊG³Q§‚t ñiÊfäÈ;e)|Õ¯)Ø‹ÀD±(n@SKñÔòx¨ÉÐ j„R@ˆ‹À;PÙ‚ ÆßQËËí1EçÃb¾Õy}Í-Þ, zVBíØîBúðvR…ÑOÈ`î?}ÖÚÈ÷‹÷œàþñMÑ~͵<ñ~ûýö˜tq#™Y/´a]ÕºÓÃÛ­Æsßç#»Ðë•wóÔÀ5¸ï¥nš¹§ gu€öÈÒ%ŠV¿4lÄ×lTE¨÷»ñ‡O´ë‡£kkG:Bo£qq‡Ã3–Þ¹¡™ÉÁèŸ!„äƒ]17Ýj³šÊ|è›%µÚùÎ7œ.Q]Áqlà5‰ØÅÕÄç+iwhFëù³Ã]ýG™Ä½T”µŠ¿§ÇŒÝ®ÜÝW)xÄvmg&’F´º¦Àg*÷sÛùöp×QßÚòmµa&‹ Ž|:¥Ç4ÞF°O¹·3 »ö†sWHZ‡$3'aŸï•P:¤.¹aå¶ÚèØI¹´›0‚²2m3v«´CñèÝvòG¨íW~;1¼*%©q «XÇ&ѳÃb»?w6ñ§á *‰Y›"•„7, 5/““&·© 'H8ÞÅÞ "I3r÷Ô ”™ƒ\á8 ¢":!˜q@sk[dYÈTm¬³¾A†v€Mk1üÉ`Ä:Û<¡„'ZÂ]­z3•lu×[3rÚ“—#Q ì|‹Q³lÐÌsqAž«ËŠ!¡#L‘°ÕõbB^‰™=|5siwM­næÃƒbE¹ákN퇶ÞÆ·BLŽù³ž¦á­º@d‡A³ZÕ›m5€æÖ6«ÂÒU­9¡kI6aÒÍT»+ží˜Gv=H6 í G~¡ÈhÀçêãdV‚0¤°vÈ !Yv¢Fî_ws#|ãguK¶ùÌ^Eë†Ò ä s¦Þ£M Ûˆ7Ò´™Á"eÃ4»ñ†Íî0s][šÇƒ’L¢c7bCXpA–‹0â­‚šé †ÞíV‹²®Öòf¯Ùø¸wÊÁ¶Á‚ ’f d¥òéYJ!”FK™TmâMª“}ïl™éSd×eŒ6¼xÉ[‡ µ/ß\Ñ6¦V¶m€èØ3 8x`+G¾g3kœ‚ &ÌY-k ¹°†rÀMŒÅ0“¸jŠ«£ÐŒ IÔ¸ÑÀí‰U,HD6Q\m1ÈHq6zÂR5-­*äâæHng™¨”ë9É÷W¿vVëw®˜Ç~4åâÌ’ï£]”L'¼ƒ¨ÅÝœ©Ó¡›o£•ÆŠÖð#+7¼õ€a0€¶oŒ¸̵ÃCÞ!ò×dlDˆLn†6ÚŒaƒZÂA] ʳ¡g2ÈŸ .@Ä.¯[ÝU¸ãž8Ί”xdåaq—¨YN ›¦Ñ˜G)UŒÍaiw)» ð¦¸Txz[ÚÚ mŽZ´8—cl<[Æ^ÃÓ¤çæÀÚ„™@$HÑaûýÒ¿˜“o³~¢ýòµ>€ñ}Ð@ŸR%¥!QÂðÝ8h˜ø+¦e’ŠV¥GÐíkŸ:² -!uxÕóóȥݢÚâ-£qê }^ž±Ä1¸;8TåaRiW·)dÙüÊ<Ú¿ë97lÂã>m›û(òñNú:‘ Pãe sœíW}Hûˆè&}iAÕôžcx†Ø_•Úõûà»Üd8C£ÝßGGd8 ½ÌP¢Õh7j¨Ãv§ÒGÊ-l¨ jšàÌYÃç“ †FÔ7±Ò A¤·ÈaŠ‘.…]A"RÅlFè‰C%ä¥/!’)ºŠËŽìE3›²¹“ ’H¤‹€¡!4d5I)!0êE"†7ïa3 °EcE·rAj0¥jªêY›·k„ÿž¸ž(››ó¥2ŸÊ²Ý~`þ§ûÞ±s¬'©4Þ¨“IðÀ½-|Uèï¬d5ì4t­aº‹lZ‘F!”‡¨°gæ³]åìxW페dÌ9 "6Þážx¶Îë¢j€Ä¦‘~Tf€¡öüôulùk8…0´›±fÀØ rç )$ ’/fòB`½³…(Žï aƒzÆÎž)3’¡CRË)J5ó2kW8+>5Ê„cÏNµdÐÛ %<~D6VF|ê $AÍb³KMF¦}=éòóÆÒI(X,¨@ùGþ[œäÞ9¹Ójˆt Ü–}WƒJ›çá)ú£~Ê~maÊe”Ƚ&N76餩_ŸQBë.Å ÊÔ§ð©v 8ö5°É4%Œ‹ Œ{~Ø(€Š² áÊŒ(× ‡§ò7É“ ’DHÄ©3‡=ÀÄÔA}hÂŽ4Ÿ+ÄÙ?\¼‡-± ÿk@ñ>¡÷{›ó7g$S(4{[ê%Û®¦+Ä0ˆ¬ƒ#¦xÂ[xyneÂkƒ'‰ÑsL>v‘³"ûš©+kê¶,m¯/;Uoµ%ÄU³t‘§ƒâª¢+°ˆ–ˆ¡ÉŒ´Ðw±ü ŒtùCà0œŽ÷Æ\hN"øU9"U½žÑmÓÞ{ïÆé8z}x‰8„Äwc:KèÞ>SovØcÓëñ;ÔÜCoˆÄÆFCv×*oÌËÔøg×%ñrd²Â`ô{)Q~÷žÂ[ÿú›7øùØÔ¡aý5# dR•U¶$„¤ÒçV —;ÎµÈˆÔ–ÆÆ¼ë¶Å[ÎíkU Y´j´I-½¦û ƒ¦*ó_C°¹º^g>Ø*2ë—íÿ©ø´â#cŠ #ÄÃû©}Ø«\}†Txùcrp–7V3WÀf\—À›p'£ÛëZÙ(-W#Ù„°oêôbAØÆp«>ÛLÔÉHRRÅ)¦„ZΤ9¤"°¯CGmªh!œÊvfP¥A0ŠUáJªÃoKPÄ~,•ŠR©‰Í®Ökb±—Ôê÷K ”\çæ­æ°50禪ÀR "­Å£lZ4[TZ‚¨¶¨ÚØÔ[E¬j#j6µlb¶ŠI±¤ÕA¨ Ö(Õ%¨­E¢ÑÑZÅE²mEZаlZ(Õ¨ÑiF h†(£FH–I Ì„ˆBbH"K(AB {îŽùÌ $È‚E Ž33)^¦9S8¼¯±uƒiXa\^Z6ËdÐb1 ^6ØRš%M* q ÑFÌßð¹«ïVÝ"4%E"b,X¤Ò”E`"€¡dEEAÙûcnê&ðÏQSÓ~@±œY†— â–L!C$D ˆd 3ÔÈþ#©ù®“êXS/î;àdßFꆰbB°í,—?‹cX·{ò>Wƒã³ÒÀ¡j»¦ã_ù+äf’;²"ÎД öФè©G +Êi¹2¶Ì’Pª²F1ÂG£# åvÈÜ‘’ÊÓ•µH6@cCC²ƒTcnìe2I‘ÖLÌÌuÖ™\r)6ì#XJîLŒ™ $d’—2‘:ÔiIL…­Å…U¸œŽæå¹“žeé||Ô»®½."%c²ÖZK#vÊÜÖ°nJÈ6ÚˆrI#H„õ D2y4i¡±³ë4ý?^NŸðÃë_Ú$vþ{Ý\ˆÁã#‘ÆíŠÈ˜Z…CtåKP(PƒiPb;¶²èU"4¶JU{S'ò±Ýé=ו¬72@PX}uM8ºdˆÙJ (@D‹J“#L‘|Ûõ˜3Ñ£5R:J®c±.@ãËÀ¾ÎÓUùÈÝø:H»ç`”'«g­dâ0/RSæYI ¿f|Í!à#Oïõšs• ŠªE±G»S¢Åš ä²¹šª»®Ï—ž]è=2…°×‹/5üà €ÂyÖˆŠ¥V•]sÂ?еŒaRƒW¥¿´ï12‡„P½>Ö”‘Ì­œ^EFˆ @Zëcø#°ùð3Úºh–æ~qÐZAñ|þtË·ÌEÌrã|)Ýäß”(£jËädŒ‚K@ËÚ ‚ÀÝá¤99ü¢J¤¹ð^±@X°UœÁÄC$±ãuÁå+¡á”Ó²›âĘé¬ã@Ƙ‹b(Ö”ԋ‰áÇY;’bjÜ0ÄÝ/MIq㯯î—sú,ûŒÂÒ·êß®r¡˜?ÑÏAcΓ߶c:IÖÊð}ÎP=:y”‡ƒ“A^­8\Éßhýw^ŸOG$CÁKJ‹´“o[úÔR"±AehDH•uûØÔK´k7—“DRè0DÐð@@✃bõä<á²ßbO./‚4Qdc™› òß»î‡óS±GUª£È·3#³.½C(<ûÿjKצƒøD8àNP‘o\Mô†Ù,ì|Ø­­K̵¡ªÃA~Ÿì%°·(^ ü® òÃDM¹°µîW¹IÙѰY5ÞËWeñ }hW dèœÇ6pùéë3ð?{Ôhnʸa1¡•:Óñëñ»ÅCÙ½gçÒƒäÑòRhŸàq3Å`v’Pýj9‹óö[ëJ®åw*àQˆpa¯é´LH´ îc™È!²ëÑü—ë«'e§þ5þþµ4¢£ð#õÐÿOµI›£6u'í&BœIZz:œ°È* ö¾‹í,Ÿ©'â² ŸÒN.±ÖûàÕö/©Þ^¯Ï8ú1kö‡È`Z6‰ÂU/ß• ¢{ÉßÀÿi¥?êo—á¼ÅÈj“/¬øüìÉÏõÛ†“Õ êyô.—úÿ©°Àf1JçlßU÷ÕI‘é§ÊN/¥Ê‹÷ÞÓh‚÷JŸÐO;tÃR§“Ï„uªE ¡P×Cóˉ†av‡ð™£1Lõ̦)pÌ»PKýþ¦—­Aî½Å¡ã&V~‹iÆÑ„2¿ ‘_óý÷~{fAª#± “h±j’Äl"ű´kbÅ$ÃTm&Š6ŒZ6’´Em¦l%Th°j4Y5Z+_©·$7йcQ©-ƒTüÇW#b‹F¢±b©•RZJ_Rûíbîä¾ùqÎÑõÇð&JaÔ£Øöì˜gˉú»€Ðžåà:2öJA"añ²Éâ åî¿y!á4NÐ*Š r…ƒü%bä]0‚H Öo’­kF˜þì”CïÙ«ÁŰ²QŽ&t“žÑ~™p<£ýKEÄß™OC”ƒUAb·ŽÒHfÃè >fèÄX;DAWùË–nžðœƒQv“ÞÚCT³„FÖ.Þõ'Þhœ6ç½—¢†<³áfMÚGÏø¼úmžörQä¡­Ø8Æor2­¬.åMˆ  [ üN¾F¢†ö¨®Ä\Qh‹¨¡“$hgd™áá¬Í«‘É=y>öVÿ§Ÿøçº,Š›îSîÇótBýÍH~RZèý^ß–pÑÝ]ñ-Wÿç5ó\MÔ{Œ+[~–i«#LúvŠƒÔð9´÷lÑ|. ˆ—ô=æM\äàÄ$`Å41T;h)ÿƒ‡ãWq·UÖ€ŠÓ_§Ç‘oÐÑ’f†.¨Üüh˜Lز„ ß§º>‘#È'øS™ˆ„½ Q©Â,«h¯î™Ž­¢›ÿ¾ÁêFiMT~ÿðö=ï¬Ñà Ãä´D›w‹ãŸ\Ã_h‡»'åÎ(™üZ¿ȳވþCéÂhžHB’O¨Öeøúº& cdi„„76IN@ƒŠvˆÏ¼˜õ•Q°Ñ¡0”¢úvôÈÿݬ´ˆÖž¯/]=kÂôª”k'¯ƒ YÏ˜ë° rHcÛ757vóë±0ŠbßÐC›¼"v2²î7õZ´KI"Œ„“5Q|›Ð®º*È 9ùB]Ÿ'/<]x¢àÜœê„Ó‹3¤¸ ´ÐÙ_^õè;CÒD$.€hGòËaÌÛ`eèä(4EÅDPÏtkqšõñ5*¢±î€Ž”è¤ÂƒKÛª_ŽØ§aÈïLÙ›§ì1æW·ÇðokL7¦±·`mÁ÷lÖÿ¯Yɬy0[Ú§,CEÔ%e¨¶¾2ìd¶ÿw~Чa¿jX.õsH¼‘G€c3–aV¾~ñw–^eÿV~>¦À©FCÒBm0¸•’ÉüqUÚ’ÄÀd–È#lÑ©Wf隌¹Þ‘éKà¨Qm…'ÛÚÌ”õ¯áLÎïÜvþ›ÇâÏâO'¨ñ,H //Þœ%C‚ºÑmš^º>µ™,³µiA£@`»(N£ù…”–RiµÓÀa ͱª{Yâ1çÚ RHdð½ÆÆ’B«½ í†6å(BDÊäQ3· ƒHÒNg°•¿<ê/gÆÅœ Ë`¹Ú÷‹“jL¡©pþŠÌGÖ@/rYKÎn0g0ÇxÑ‹UínÜ€5¥ˆÃ÷`ÛCSf÷›ŽP~ŽPÒ€¿¼ËXVÒï—æ1íKÅ$uf"ÃS4 …b”m¡ö6@Æ*ØcÓ®êcaV(ÉR±MQ•TÉEQB&¢eÝÐÊ{8CŸ˜ï™˜˜¦xlÇÝgC纽¾17Iü<‰õ^%|wù(qé¯D^% ¢1yªjIi8+F}47_3J–Ýix%fhë:õ—©ì}ý×j¶î¶,VH c`¶–Æè hiÆò^;kÆ¿ùÒ„a⽯71âæÅ.¾7à]z½¹W9ÝÎáÙvg7öcÄoV“Lè“ý(ݳéêù9"-°‚c#ìëÃúÀŠ%¹Ô‘´wÅ6…ㇲêå¹$ã…©b‘3J„6ÑÓo>tNt,ÉŠf“§b ¢¢Ü!³­ð‡u‹³”œÖ½ü~KÍHêŒVê º‚в0Rªš¢¾»Ûk‘lòp3„ ¯†Ñg0™]$ä Ü·´ªà'7ãÕX=îr nDï¾¶/¿21…´$¦ÐÄG˜ÆbÒ¯3Ž“ÊV™bƒzz “†pÜ~–lЏoq‘„[²ì[Xc&Híe­ªÆX™|åTY‡kx öÈ–it°ãCB»à¨ØeÌx™'¥*§j~¿õ»ø Øwoz…ñkSž?ßC—³Ó¥ÎBÚ²±t–±d60$Jˆ^n”]‹‰ H9]½'öDèà9Æ™žg®ã®/¸©ó¿á÷ynÖjì!º"R ÁŒ$lc=5ÉUÿg¹ƒLŒ $K^M;sPF „©k¬7—¾ØÚƱ¶£Ë»óÝâå׆¡dFP„–9XQlŒ‰FIØš"`ݱ(ÒŒQ’Áå¶DF£PxÛ¬¹“1ÖA’ "þû:ýƒÚ°ðÃwÛ;Ù+Xƒø´Sç÷3?²Ì°Nìˆü]½^ü÷Ãö˜pc'ñ>ó3‰ÄKç$môáBضzåCáÜà–ñ#r¯Çxa¦ä…Œï$ÁŠHÒ~xH/8Œ&YQ\MIy!„’€<¯OÉ©0Ç( žŽ¤4L ¥‰ €ñ*ÑP }þî¸),„㯳Îã8Ø(r±L‘!’Pnxû†ì5ÖÃ|ºá]mÊi Kã}Ãvp·ƒÇ ÛrÂgÐÒlÏ(÷ÞŽáFMü8kM½µ.µc1ûøeÆMPùO9=îÅõ]a¬‚r”’yÄz4d1䯖{:ND»äe´ôpíŠAêËD êáè¾³œ3âè9»… /ó21¡-€ögd²õLf’æÇ ˜÷ͱêBo2¹¥«…˜2¸Àh¯Š èÖ0…Mpi*’á+Ô'ö”ÕB/BE˜C)‹³Ý3T‰¦f™ç– Î'Í(PVꑊ*Õ@¤n‚³kËë]’sz3C .ÅAŠ“³nÕÚš7gn‹»|¼ç-\¦#!^Sxñ)qðíç5é^/UˆæâîZÂà "£F*ˆ†1w‰”$•{ó^uצóÛn1À„¡SWZ7HfÈâ¦D!{îeéyç ¡”<îÀÞ•ã Q{-%(•Th…*Š"gëzד ßeÜö9éêœçíI!Ö8ÙÜS{Û¶R„k”r”Í ìÚF†V±æ=·y°¨c²¢êbYaɸóÿÒ÷˜a¥$f\v~ÆŸm4=œ§DO‘ QÊH Œ!RG»%†ÆÂ›k—Ò`UTx "iÃ-Ôm™ÿ?âO{xŸ›ï;µˆ…¤†vŽAº7(oIJî÷9òí}\Ë ÈçIXÿ8äf³¿ŽG—ÇêëN‘<ÑŸChU§²«2+ER²€Îbm;ÛÛ¶ÃÃN<,,…#lx83%â5Yš„ŒÖ2á»ß#Ô†îoƒÙ3"Æz?ØeÔ6àé´|v‹ |„Ó9& ŸiŽƒ”=_?ëÙ[uÐúÞ¹°qÝV)²(¬šŠ%ÖÃmÝ QƒëVìjÏDµWÄ¢bS(ÌŠH@€ª¿ÉÅJ$ú$H NBP®®2ŪLcàíÑ7 'ón‹?A)4ˆHZ„h_©ô ·Ø‚RàM'¯5:Â?8•”4 ™³Eª’»u8–œíë¹wÒo}zÌò5Ìskâe¨$„M!n1c&ÊÃZÔŒS.S%„`HáZ7§$ޏã'ÅŠˆÂÙ (Z©ÒÉRI:|÷ÈÛðX;öö]ßaOãBæl6(÷ûoÌÄB0³së\Ú«…­ÕêQ¡ž¥mÛƒ$# 4´ÎqžÌ*ó°ù_Çá×Õ8ë΂€jÐ lf¤qŽYéý”^ˆ“ e'(R©¢Õ¶©@—p1Œ@P«coàÊf¡×4Ú+%@…h’1’B¼eo² A¢¯Öµ ° J-›cM‘¤™¥—‘Ñtêj ºÖž²,M¨!¸Lk.1«õEd4ÅGI4T7Z1§"ž(Ù†3F²²Cm4´d¨Ûc"ÓËa©­i7­YŒe ¢ÌŠ© päÂÕ€¦¡€d…‰Ös@ÍÉ$P ai3Å@6 ™`+ˆ¬‚1f3) khm­ªÙ‰³ lÇ•6Z¬AZb4Ö4«1ˆŒM£2,Éiæ Fa6£lµXÆky¤ÓÙÉ °Ñv{ŸKW{YüI¾úgj@‘ÁÖA¾9à\Ý ©yv• ¸ ì¾åßè©?„<'‘¯C«3ýw‘ÍÊC>jŽéì¯Pd„@ÈfSFÔùظŠéÄðÅUÕ•g5(»cŽù|æ,Èë¶Y\÷Û’I/-AJ] †Åã뫤Äôõ«4tSU*o6«A6òIX„Ô´(ÜŒa~6´a}»½\ZÞõ¶æ‹ëü5ÓÉ2Ü¥Qnš·k6ܶ‹•E·«µQµcmQ¶£¦Û\­^Ö‰-&}ÍžngFzËáÒí?›· ¦}Ϩv’Ù€8Ñ8n᭠ÈhO<#4ÃѸyµ‹Ž:h÷4’8¥ôFàCf”ÍhÏØxMàµ*Tâ+¡¡dBa†á —¶ ä€~ ÕAHKQ‰ŠÈ%µdL‚ï¿ÞQ¡9+ëÍž¸qEw¬z¢=l¢-:§Ða$ð{ºår³¢X s>:ÇÎõøµ9 õâa(›­`ÚNª%‰Äß´C¯³¾TÚéì>OW‚fd/Í!S>íÝQ)P>wèjzoÙÎÿq‡øOÑîµ+N³4Õ ÂŽ6ê ‡eBZ$bU7…Ø~J˜ü .>aæÍ^¾ò‚œ…^uܯãy— 1«š¹Êõzш‘€‚À`Š/®Ì0L_§pŒ‚HœHPJ¨¼ì ‰Xx¸›–×on×#FöÛr½<[{½÷·µsÍÏô½$—ÞÛx£k•ãPE/«ÖHfÀÌd‚80HÃÓûœå» íbýl>gC‘°.¾¢ 6¦=³œª¼‘q•¦ßdùn蛺Ë]vÉÕG{!§™§LÑ ¬³åÝa u²F3Y zû.¾£?QH‹ÁׄPŒ•Z†6ÐЈPäŒF £m$c5á´Y6C»Ï;»”¹æòºxS!hÈÚpd#"òþZÄ“Ø]ùÒ½ÃdÉ`ãK¿ž>å§-Û&ÓþiÈY±5`94‘ÃõÐ#èÎv.®=æ.H(..U9ŒÜxvj*–ìRÍÉ9BÓ$"’&ü2\«—m¦1PP-qUJ ,´ƒ„)ŽS÷|x¶Ð›²X_“ˆŒ+L}8OT{é§6¼êÊ5m¬1ÖŽ‘CyedjBÈ66ÜèÙUêÎ< 76¬Þš,zÖ\+œTÚÆØÞdlM"0 ÁãºxÌy±Žæ`¹S”ÈX ,häÛ´Á èšFµ¥œ^©­íÍF +7Åh²å…X86³"Ï!¬¨ K¬\j·lV0ÿ3'%…cI6Ô+³Ï't·]Ò%Ïû[¦Þ—su>nâ¤FŒy×\;j°³1­UÒä͉Ê,Û•U64«—Âß(WŽôˤîŠáÛÉuöÚY3!ÆÑ•±›²VA1²‡iÖ¥FÝ[÷’I¶¶àöaFA¸Ñ¼*ÆÉ”˜<,ƒ+#Èt©¦š†¼ÐÀX‹HaA±]¡ôùÃ9ÁѦÂ̵ ~fh¦ÌÍN×v$i6› ?3Ë1—k‘º0².¢Œæ°¬ì´Ã,¯Si Õµ<ÊXûõLÓcã€7³Z,mµêj#6u™#jK)\Ž"Û Ek#ŒV2*öefBHcˆi…q¥Ø@mU7ˆBêÕ+l|d{àÆÃ&æˆÆ°i@1˜àÚeIØFÛF¤ÐÛN@¦2-¤’4ZI" 뉌a) ÑXlm6HQpº ÐÆžOA1cORx&ı$¯=DõërEx¢í²õÖä,W©"Á:Â4ë…ŒgšÍ´ ßÝ0ªl‡%Qâ•L·Õ„W> ¬ËÉ9*•aíL9nõeƃ÷Œ–vÿ«Z>Ÿé?Aðm€0„Ä4üÄÝ˼q­ÃÜzîœãØ8ãÛ.Á(øhÜ¢P”B%OÅ«å캯Ú•n‚F®scX¡8²èO‘AQdÉA<®óG„Žœ^j#h¯Õð”ÀôPóø¿ ¿ûÇÅïàìà‡q (ð3ÄN~<„Ŭ­êÜã¾E'kç!ù?…?ª''àRv;jFHýÅPû÷2$(™ê†Ò|¹•y{á\ÕÅÖkµ2äÕ¤LŒîR7%B˜#TP"Á¥¥¡4®<mÿj|³?7—’ø¸>°žÌðÐçÑŠ!5e¢Š±ìX7æ[Ð.I$`ŠHˆëuÈù¨¯(Iá¦ÍC1,;‡Å°à:Ù«dÂåéá¿åëÅ>wGƒ ì9Ó6Æ÷Ìý„1£ Au¶ Byö)›3Be¶îY™ä`³ ÜÓŸ½þLÓÏ#)Oæp'¡„f²)+|i@1€OQÄÆèC°¬ r‘“ ›XÔÞVI8ÏW0¤-Õ–Ûiƒf[KØy? nG¿œöšŽ0õ]Ÿ­h‰ 0N{K!š**L\È{0”÷ĿՇs¬Õ›ZtÛ„,;iFDW!ëU{ñ¿j¿ÔäÏYAGùRÅÝj Ýb¬.]T þšåMè‹9²dFHP4â䉓%)6µœ réòÕÔÈ J¤e"Ô£‚ }¯¾uÝt¾èîw—3wyäN±rØMçCFNR)«!•§  AB˜¤Ë1.öÑR(S xÿ=ÈLjûbD[½$ã@³@ÁxŠ"ü `Õ¬3 ’,‰Ÿ&î\tî* œý—ÍûŠœìEÅ<ÍÍÂR–l{È쀹°ø!y { ÆÞsk!Uƒ;?&·RÄ¡SoA²jk¨}ÿˆÌæ8ÎK’·òݾlôþˆPõø©áßËÎB$ß&GÎõØžM”põ Å ¤á÷‚ÏÉ5 Pÿâ¿xÓSâ7¦(±u÷õ?¿!×8 ^‹&² ™Ñ‘äÝS’Ì¡·‚‹Ü^©@â`Z¿Æhpˆ„ƒ–ë:ç°›WuÚé\oÃß?Í«ÞC¼‡®Ž$1ªÀ/BÅew|ë—rþÖ“‡Øƒ×|™ÅÙ=Ç×èxK¤\èpдW8D–‚ýÏáW{áT ’r²- _ä¿\‡ì§îx“¶vÆÈEqF([n’£¹†ƒ°óÕðú Ç”Æó€›Â¼fÁÏøWÝ):²£ýÎj‡Ï0úlŠ ëû¾³Ï€`ºóMˆ ¦oÂë÷63³_5ŸÙ7‚†gAêÂs2Dfóq8Nš³fl"’1€/´ìø0´¤2ºçž‰'$õšjè^åŸ(¬d›BñF¯ÔV¹ã–®_B¼nW,ba""ÂÖ¸B’“ ‚Àà2e·–1ãr£ÈwÌíFÚ2 o…É(,$ÂRí¢•X0Õ”–’ˆ ˜‘k6OÒ’…9Ba!?$YÁ¶vÙ«‘Mªl]ß9ö鿬Pu?­!_ýÌåÿ5‡ÁÛJ®®IjÅ:’! É;ÛÈ™% £S‚Vµ\¿¢ìOÓ¿û8ü½Åê·u‘Å0:?ÝGºC4ÿ §„Àú$âC“±DÌ8¨y?ON~\àq“šÎÿ{b ì ÔÙÿÍvÆeÿ\’ƒË!mš,¦9¡UAHÊ"”rqËüß‘¦¦=îÊÄׯÄg‘ä#8xúâsýžalF,Cα|FFÆyðnOÞ{xަÌ$‹J(*2CÞ:§"MìúA×-@õ 2ý“@Ò }L7ît^9G[ãñ hDâÍA‚pÐSt€Ä¸n¿*ŠÕ£Eú¸JÐäýÎÏ@þºe㵞Ù;(hñpšë·+ƒ(ácegb«I.­Û×ð'µz¨5¬Ãí´ˆ’ma_è»_"¬þzÿœéæš¡·µ¥…³±ÎL"jɤÛ}èOöçÉ@¿ªýû·°´Fv5[ºèk—b)­jãhk}MöþIÇ­®O©5óµ°#l‚°*ülM8ûjýÿz¼ÊàÉ$pE΄KiE DÛóÜ|F+ûO½áƒ]Ôr;ê&RÉDYÏn+Äg1‡ÄïªB9¸òÒZ=iÉþ[VÞ(m™•¿<ÛƒaÊâÜóa‘ÀJeÝïP¹ÃbÄ…±Ê½o\Á=±£%>„.sƒ'TaC%•ö“Lo~®+ĤÞCE=_½‡ûsï§jã4™ áëÅÌy´LíWÝ«;*õ×ô_gÜ6-ùw¯=Ð=ÿë5êúôžGãô›_F¦‹Ô/pöq)Ôµt7¦KèëÉ^(åã†<Œ~_·ejWá"=pª@ÁÔ˜WéGZE¶È*Êe¥ ²UT|8Y0)X ή¾‰íîò›+Æby\ž¨ú—Ip7 Qh*‡S–ç\†(¼Kb[’@H´'“‹……¹BHòU4\YC¤ššÜIû0áŠyÃLËÎÛ+3›X£—4r-ùM$&bñøqŒÁ$;W%>(7‡Cl¤keX6Qi3Ÿ ø?wù_Ûv6l6°7½…¹$¾ÌÌë£\ý:ÀÑꄈW£©71DV(r yb­&ÒŒm¨ÔnDÇÖ·G ©lTmTÁlâÁ¯Tq_Ô¸G]š»-¢Š¤ô|¯ûÏV|taÙãÅÿE†0:Ø~É«ó?x~— „õb4IR‚ú3>Öú°Ø{ÍÉUJ,õÃér»ª?‰ø8±gÙ&\³Ø¢¨1A_Ã`F‚H$m`N”×%ŒÀ‘ÎáTJó$ÂPAgF&2;6p–èǤƵ’œÏgå¡“áR5e©ª›“¶KA«y/e¯é˜u³~ã·1V_¶Î±e&2¢ØñPx§ÝbÔ &iþÎï›ô]k:ÝcŠ~3¿uu2øúÆÂc”fI¢AM“‘¯-»8X¢%öÍ5Aö;+K’Œ'Sˆ‘Cäg´œ&°c P EE59ÓY2xˆ~3qÑÁGZECAKÇ+‡¯è‰³‡ ±s|Áª2Qöù©xÑÿ-ý3q¿Ã~6i؇]bŒW’LÙÑd@à/nàn)M2üPwÞ73t=‰Ä™[88Þ¦MÜÞp¿{²}zL»5\µ"¬:˜\·àÞÔ>õíùtlj/ò|<ïÙdR˜B–©¸yn7™-th©0ÆF³Ñ ?N¨V69"i¡ìå ÈȶV Ô+Œ¹+Uˆ“£N c2ÄþL²¦qâa&•†5U)]i•ªÂÌ$*m¸t®M;ÅÓ/…Ýç^¯#©»¡YlD$zp²¸F8âB$ƒ1Á·’µÍœ»m½µ­q|¶¾¼úÁ×÷ wç¥5°/XŸô´ab&VÂ"9p©ÉžÑ$02/z'œ9¹µ6se˜šþf]•ÔýSA¿s8Hf„5ÕzhžWªkCdãªÝ®çÄ8|†´Øø&V•]|,Y–_I-*rye$ö  ¾4)WféqPc L3µMãP,Š"(±ÁÙü, Hë>K³ÁrÛ™“*¯¨ÛEmu ©¶o[r 14•i4XåtÊJfP˜ÆÙ~aºŠF˜½¶èo• ÃÙÐTÔÈ-BEŒD©™ær©oj:¨ h0ݰG4Æm5‘$P‘MŒAz×!€2ö›÷³è` Þ^쮀S¼9·õrÊ™üßjŠÃMG&.ó`tõŽ~7(21Uc²L®\Üœ‰3ƒ0ÂXÉ› ØÐOÌüܶblsN  ÂhÞ}ÕqÙ !TQæ0©F³é)m cÀÖ…†ÓË®^´^:ë»jVÕÕÛïþÅœ\(b I’²âÒÙ“DjµéÇœ|{§r‹!nn™1zíÆõ*5v¤)Ú¼ÕżÖÞjë£rwI¢Tîí—w7Z¡ÒŠ) [Ü MWoTeÕ%¶ôœ=lчÍûGB}ä¿eŸ»3&nqA\&ïÊktöðΈÍJb/_x€øú66f*ÈÔÊêÕ‰°cn[ر0’…$ùsè¨2òj†1‚ˆˆ(1ïTZbÃ:)ëó…¶’¦ýÕ=FZøÑ™‘£cѰ´RÙFH5 ²ã{kß^ûפæì^OKÊ“ÎØŠ+mÝns\ås]+·nñçŽéÀ¡tS-ƒ&êÓ³6Û¼k+ÓwbÂ,‹P1Ãv9Ó2…µUV”ª¨Â†&&îºï´ëðÎõ§ ×wH”RÅ0¤nvÝ•’©D׎o„J5ÌŠ6Õ²±«õG¾ûŸì~ÛËχI w d@4²¢•še)'&µåÜ:ëa% Dæb !ýE……¤UÈœ#·bì†'Ÿäª4UI GпtÓ•7WW0âøû1-v@cN¡ÐI¤‹—˜0â Iu--)4÷Û „Ûâí\˶þEØ9Q¬F&ìæº© {âD³.AΪ]óŒL^÷$¾°Õ1jàgù„´³Ž¦?/pó›¾%Ä ¶]؇%EŽÚKAD<«74éŽUÝ^gQå›ÁF¢™É´’ðɼCh½HÉà¨Ä]š„íÐo Ö'R¤ UÒj6Ï #xmVnn·w†ã-Êë–©sqáš žað Ýmw졊GE´tZ ¢HØÕÈï×õÙ£¼°ýgô‰7è÷ÿ§{½Þ ãÀÌÌu~L8Xpÿ§4ˆcÖʯŠÌeÇúå˜û8a½7¤Z2“y“äEØKqx­•¶óA_r:X.´[_J,3¿åh7zà&ãkT˜ºz†áØÌ£&¹è’)ó¿KÈq}£à\GÉðû; î[RÖ60=T_£ŸÆ>¯¶î2‡@4¼èlô¿8ÇçY[­8²¦åó°€X#+¨ƒW%±õìßð¾>ýŸü³³¯ëèFŸd^<œí[1wvôÞ!&÷xÜ1‹5ÙX¬;ÜCzä¨jw4¹ÑgÐ# 0ä×,6ígå³¹ûó„¶qNwzïÐüýæÈnÛ½PÍ—tS6nI¹!ÄÃÒVrcõº¦±(›´r\ßY6ª=0{\qéÝÌ»¾†ˆ×ÿônÜ×4 ±$ØD[õ?)¹¸¿%2·ÖŽeC®N×¥‡ bl+‰öÅs­÷a7síía»¨¬º„’ëC=ÓÔ#5-t4<6›±O[B”»[f ¼ººM´º±R j͸\ÓÕÒë‹!c8ßðFØ®k¿ÅÉ\g‘Möç¢áîSÞxe;Ïvœ²,ë§"ò0´³N'žÂ3Ákªº#yfšÕ·l™Àù)—‡_Z2užò6Ÿ§¥Cã¡Ñeûö©ì“‘wG:£AÓ ~0• ¬=7—érÂcmíÁñøÿ΋îÙ¥‰¼˜BŒ‹V/$¼Ä*Å/ßfö 昜D÷c‹j´èÔcKf¶q¤F !zŒ¬mëÒˆƒ…‹gZ&­Ø$>{óGŠ4:ZBIl“ôïô-‰·9¹*ˆmKJH(RE”ÄL4©"ƨȚŒÿ7íÕüþG ´ôÅ=ÝÑ$ÜM5ÂxÎþc‰™¬ÇÅ~ÍÈ xÎ1 ;r÷_‰ú,¤(>m‚÷„j‚‚…–¹öõŒ zr yËNzÓÆPîf;QÁ*:>ª“ŽšŸ–gi»Y´in…¡46¬kÎqh„?1æ]"RF æ].þF™„2D„k‡þX††”ª©'LÀ ô ºŸ9C &¥_ÑþžGAzy9=Óú힯|ê>[z Åûæ‹V>R–ôW°'bÛ’<-ĵ;ˆ¾ L»©0í¡¹ã¯½wûíe‘Ï74Z®Ë'ÔªÈô‡æÏUÙmÎ?úY¿R,8šüÅYq*ªDj¤C®4r0Ã‹Ý À†,P¡Çëû’²Ê‘'æ3Éñ뤥`®W+¥Ðù•ËxPiücÜÆnÆ3 "iLQÖ+åØhaw!C"Äó\5é*’ÏlÏ)žÕ HwPÁ °sy….€æÒeßuן·94¹åe`»rÆÂɶ³ÎQÅšh—Ÿ3”’H±TŠŠR’k#²Ú·00ÏCã÷r'RwYö½Ì¬údÛžÛ~1FøÆZ 2P_Ôû-?Æ`l—wçTñGË’7ZšËl‡Ðë1Ím™²3K-xõchÖ–¬ÊLÃZ&³1Äè`fŒÄj8bÁæiÒi¤"ÍdC‘(8„Ї‹3©y/;ØÔUª)ìiA©Ë]ÕŠ5eâ =‹ L›¾@ˆ4ç®szf{„…²/…T}«)ñÓ}ø×:4hâõµw4JÂCñ°mXŸ£Ãö.èN„û‹_8$ª1È-Ý‚âM¤6 íÉâû×$ཆ½/†ÒéêkRC°–¯Ý:vI­w±ižS\b}>Óó~s5`ú9 ðe(ü½r31èæíIþœ‰ò¿NfO•ã?g£véLâî¤:Î%Cñej©CÒ6áþ ³ ‚ý‰‰L8IH¶pŽÕ«ûSàŠí,ôgŠ©œÏ, ÝÂ2ºä~’·8´Dkœe¿];uÉG­i²‚Éè†mC;–íM•%ð ³ 8Ô´Âc«ñß=¦ÆÂòKoúÜÿ˜çŸ –î66ÇBé&Ã1Ó[5eœb¯i4qûnbsôZÖj7qìXúÑßÞÏÀ­Rôœ†JßņM8qc‘Ÿ(ÓÙ—osZµ„Ãxᩆ™µúÕYÈ• ¬VÃaéÂȘZuæ$Ë™.lÆøê±‡^Ð6Åû#ŒÔdËU¨3¤ pÍ7µ È+;•Ó»ï¤;Ƭ¬±wÚZ/·¦ŠšòR;ÕÑ2º2ÁRPŠuô¬ÐÍ»0f8I:5Z|l9¸=DØä6Ìu®øå˶“mhâmnoÉ™«¢@˜á·qCB\¾ˆg)DÔô׊¸2@W–ZÛòmÄĹdÄo…Æ7Å‹G“ÇZ%¬|¬ñp·R=JÒÆlõ2£ÁîÖdÓGdêt„+9d7qÂà°€A… cl<]˜M1på–¥X`‰4,ÈcAÉnm– ‘ƒ ¢;p¢¨é¯µ…».Ѿ9N³nE&™ö&p1½Cª´u–`äzKµ÷-ˆ¸IìuÃ|®3”4BB-©+6i¾V6gl 1}¸ÔL"¢+Í„ç´ÕK«K¡SBîÁZæÝˆi=3IÏ uÓ ÁEîƒX’|,‚]Õ€þ÷â{d_˜]ðd.~üÒ‰Áîi6N`&eŒ‹Î™^ôÁÁ–UŒ0y)0FX;ÒX/s,.n€£Á²M ìÀ=\  r¥9°h ñPùLÎ0=vÂrbQJ"^ðì fS Ð]¦$Cœ°9zym;IeŽ€êáÆMƒ‹=p¡éÞã‚ 2Î,  6Sâ•Æ “>jB‘hZ,(»CZ ”‹È!°¦U‰°á4?@?% ó3m$àÍ󱃸7SgA)­Â7Á j…­g4θ{Õœ][oZw÷Wª¯ƒvKøHœ{Eðt® ‡`hžb¤uRHèJ/wO#Ò(¿“=Ý´fîNZ eÛfè™, 2XöQœŠ.^ÐÄ`ŠHNHƒh'Ê®”#×L ˜p¸ÜDãHpë¶îCÞèŸ_÷ÒÙŒ_ƒ ðïáx¿ /ƚñÌMÕo¶~8–eÅ·D¥çU܈ ž)¯¯Pó{ó¤Ò †b ç§Î•NO:€Æ¦ œÀÞ&ü_¯oP½³ƒÎU[MÒ Ûéj—\ÄJ²‰ÍȘàÓ`¶lñ¸ë^uLòá¸óàzž,\—èîìÛÆš‡$½X¡AÈ;ë³Z°w„áèµúM/ÍÎÌßÁ7u,`9œ},/EÑLšš´½IÁÑ`ãÁ ÄÁ1ÆmaŒVŠ/ ¦ò” bZlàGÝ\b.nṈ̃pä\T&c£¬^ÄÕõ–œ‡!7d¢ƒ™±?®¿áNÜ-aêà+»czö×ùí;=†¦€ 9vëòEXhÈÀÖGe£gäpÒ÷q7I¸nÂ3£/…:Îïc\"àp¡§æ™M°2Ã2dÔ­kGÐ ?&ý ]8·ãp„:ñ6*ƒŒŽ†ú¿´÷Øs hn`¡ãÚÿàÑøúóN03±_ëjºX¢Û°å¶kטöÂ~Ö¦ã\ çôzÞ` _¦ - b4¤i¡µÆ)±Ýç¨;qß’Þµ8œ½=/µ†XO £†v\ðÉ]X+å€ÁiÐb¥hãâ4d²R\äÚ £)¥}¦$kÓl€¹+eËïgµá°íÉúŠ›‘‡¤~ŽiÕ™roåÚ¡,ºà†ÛÉS“m“V N±»ííW]°Ñ˜Ô8í먛pAÅ­«1Ù úýŽ£¥¶’fÜIÊE»l2ÅÕÃH\¸ µQmmÓ¢UlØ}ß=)1E(*ì5}g¥”±^¤ ¿cF¡*ð‹(5MÙ\þ ÎñËT€¤§®«ãÛ[cL_¶¢ƒã¿qu½û¼õ¶N†ôÝ=¶»gvRCŽvÈ,ˆ¢¢£<æ§;S¿ß Ñš¾+˜ lÅxŽÍ÷­ÊP¸ÈÒŒa|Â-H@ìšF†¶¨ÛPhì¼;u£„ßP¹¶OŠÐ‡*»õÿaƒÎ;Yá2ï[€#„¤QwtìŒ8HÆƈ£DV ´>ØÚ”ÊÖòåwšõ×§›*è0DLh’¤ÄÍ.»zóÊõëÄSß ²Pz½ÕÁÞßñ}#·aW83ÇiZmº,|É0pÓ¬6Úk4êlÄ8ÈÐÁ©’:Ç"ípuëQŒÁ"·urPˬ“làÛáÿw@ë§_ò*sx(ù8}hîñÒsg)nzênö¢@à ¶ûtŒüxü<öuàH|È;xº¨'MÙw¿wì_Öÿ¥¬õ=oìò>¯ÔÄšèr²UF|ð0* ѨÈ/ZE©³¼×„B̼Qî'ü¹?ªLNú‡½ºÐaã¿´ÛYâ}fûé «Ž¢–0Ææ?|¼6b±y¥DøüUìþ…Ï2Cãù#êõ¦ aÜ6ÊÎïªV±ÙÓª–˜õ<Ÿ[[ŸÝõUô©Ñ¾‰bPŸ¬†çÈgÎ+|ÿX$ð°å²¾ •äb÷88š¨Œ5pþ12D0÷Ät‡~ ‘ (ޤö]"þŸ*ÿDS(80Ò¿V¹¾Þ'þê_1¢ˆû(s]u}?ºaúáÔ}Mãø]×ÃÀúµîg3¹é-þp>Œº ~YÁÇž›9"ãÏã¢ùÿ¨‹ÿÉt.ž›½µ=»P~ˆ‡þûÊyH<ÔO)2EùPNÓ½×üÛžZ/#ÚuT›üCÒyÚ¾'§‚}Ooò¬»OãIŽ uõžBZÂxò¿j M Lq” {WÓƒèi³ñç¼Ô€hA}†ïF×çòšw'y)éçÜŠz(¾ 6ð dèŽ¤Ž¨§³Íꙃ> ê£Qdhª(9¿ASz#!1§¢Ÿ~w°O™IÉÐl¢‡ÜcÅPyh ÜíÂiBGRÉ›ÄñóºÂƒÚÄ=,~d|ÞÑßYG/ÿšBñáÍCÀŸ9ˆŸù‚üItñ±êᵋí&õ½z«„>ÔñYrŸ¥ôÎÖ{ˆw1=_Áø´¼ |!è'¨ßƒócú7úþzú|\U;¨tñ6HnóìÀG»¿î)ë5#ïûmá0ÿ5pÛVUÓ„$2AÛAõ,)> º‡‚iÿ;ˆTèáú`ü|Ú:)£ßPì!ü z¸ôûŸ-Òp~ægꃩÍÑ÷ãÁC€úÔôófôó ñˆ–]ðû]+ˆ%Òóœtq‰½-&Ö.d_S8›*­i¡8ˆýUø© ¢WÌÔ…5†ÕX,©nV ä\­í¯<ãznQ£ÞCq½§öè^_H7QŸÁΚ7¼5§Iû¦l°qâŽëqþÔfÍò›¹Þfôè¾cÖQͤ·ß‚E4ƒ'NãV¸#Ù$ ²Ê³Ô‘`€@‰’øƒÏÎ,Uî ¥QHº3>2.d{ä • 5ômñÉ¢•ØŸoO€íÅLTMÃ85†“ý´#ŸxO^+eí|†lï*Ÿ):‰ÒÀ3K{ÓËX^11É0xv9w2XªÂ=¢ ×QÏ8Öë ¹]´ÌøÈƒ/  V¢lŒ"AŒ}R6µ'6-fsÑ깆ñ¸Â9NÛsUyOÆø^ýAH^ß.‰ãuéu'w $¤i2CJY™£—[Ó›ç^ü»ó¼‹ß®xº`Ôo™]”!°õÞ¼eÓj•|;Né1\ÝéÛ$GÇ·Q04¬až—žUPx% S(©£»¸ÙzYÛ»ºWp»¼y¨!ƒla"QðÈK3ŒY‰‘²7¬`Ù ¤R27:7H„i–eDfœÙ›Vórì×Q­Îg0, ´÷¹¥\Q±˜¶Š`1¦„£„¾`ØœkAŽayåÖ!HBD‚M¥ AìcL™€kØÉi=y¾áü=¶n1Јº³VAÎ8]9‹\e™üP¡NeÅ9ööí‚b>?7àÚñQø)¹ “GÅÙI Æ,APr¤<Æ”^íWUÔ´q³Ê÷aþý׎úGÉôÖr$ü¦Ú!þ É>óo…–ø¢Ô„sâyûé´øJ{ÆÄvQG.Gü" úõŠ€Dd¼ š»â¢`Û«ÄgHñYío݃€Ìž SS>„äeäCv•$9x†œyè'áŸ/çÑ¡uT” &êð>kÐûÏÍÄ!ø,Õ'öX" ãÁZ%Ä‘ÿl%'ˆæ´ íöß[dF£¾3˜¨]_"/—ˆzX¾pPq¾? ÁI ­mÇÞ±Q/£ªÊgóæ Ê¡½)-)ƒM'¬Øa’H !™²¶ÐÀÔðèd½ä}ÂW‡Š2˜(E€m`|¶u&†ú¸j¾Ãjèó|× ÊDq¼êØ£!4$vçØ9@åšUåÖiL¶eB0ç]{; ¸†™Vˆu7ƒ[¦·ve°MÝV`MšÝÅî¬Ý/›•Ñw Û×íÕMöMkºðvÿÑs˜Œàµ˜‡l°b0ÁçîBÿЭXœŠy<ŒI¾¬±šíÍ4Њf645Ä7þj°O2QEºu‚Y &’eÅΤ—Ä`M^É’\K’!Lƒ±»ˆ ¦Q!í”0E<²§Ã8IºÈërY ðÖŸÙ“ëVÀÛhQN 0b7™SÆú0ÅsvmÌw¦¶¼ºF¹W8s« ¼Üce2’ Š…ì*¢)NàÉTCØ0*.̃“eŠOÛýÂw`N…ô@¡dWÞÏ )<£©Ù|X*B}](&°Òjеr#Ã8X Ä+݉.;=|¾zyÙ£L©ÓýeÝØD–º x”m9j»©“È .Áö¢ÖÏÙ̘-“ S¥~šÅXðÇ…³ú¸H»h½góìŸS[Ww™Bÿ‰¢OÆ¡bKPÕSE¤Ú¥°pŸ1£B`$†$Û2AžÍ‚¼¾3èg¥;ÐÅË*XHÁ{¶'ASªçJ±UJˈa²š‹;ßuôw ÈêÈ(›î5&¤æJŒ%°¤/;$ÆwaHÒÃ&LUH )Q²"fy=œCÛ’LÐ/‰øM ¼`©µ0ƒg&qÇâ‘J͹G3.ã,n$_m $µÄnl®æ”¬(Ë%—˜;â MJ•"€ˆªÏÀÛ¡û5ιn7ôÔ”†‰A×( â$¢€ªžÐÖn¢ 0S=+);îÓµEŽô1¥©cŸ’1ëP£,ÇUB‡„‡Ö+ØD@Âå" Q¤åU™ºµªö2ëGRÎÖÕ­†Œ=ìØ½IGÏñlj;³¶³yØÇs`σþ~*ϨõÙƒr¹ê¼FK¦Ï ‰B|«:˜Za‡hBÓŠ¹þt½9Š‹?äê5;æé ¬8˜b}n ¢žÍ¤3HR^§áÙKæk‰åô¦^³ÏùÛói^ÏÐ’ç8ÂDd&…ƒ©bÑSƒlS—fVC##|¶Ö£=Ïs˜pmÚA¤hæHƒÈµÀñüí,¼3A)>ˆmç äO+[„¤èdýdÓÑÔòšÚ’“PÙuj Í­*1"‚À=³¬ÌÓ)ïöüÍß÷³ÁÑgDz<Ý~$#³øa¹±Ã¾O{DF›q²G”P]©Lª8›þËa“y)ˆ”Ïô´òàÓ¬Ž1©Úâ5=Uéβ7hס™"ì1@Ì-+‡1`øõ¢¨Œ+ÍœFQgúÿvòmÜi4­ãj¥´tR•,Áeª[9ri¸JSήUÝÛCÇŒ!IE- PÝÓÈ•$eí²¢ý"û„yô|m}•³&¦[o«Bk§ ž }«hwþ«ûú57Õù—.Á "^KÇÐiŽxðf±ló8ùøYL§[³öóiË¡¤~2‘@™²Ÿ`Y]bÅÓ¹£AâQc*Uq`¤³i09’ÆÂp>@ì}–ž}ú7^/nySyCÇ9ÙÐsB)1–\uëå(Qò!$öí†Ç¯±‡{ލIÄÄ¢@G•=ïÅ‚½¸R28…I„çòu*hQOßV—Þ‚JÊ¥0ö~ëíïëÓè§œžjx1éý…kš”Âd€gJ­ˆOÑÍØ=”~„:X¡”&QÄëÂwD/˜f@´¨ýØòÿ¦ÍÖ›èÕ‹x¿ªagŒ~g‹êpfz˜¡ “Èj´nË+ ´ñpZ˜ÄX(³‰½Ïñ¿+Xç[/Tƒ¶²m–³¹-–®¡iisda§P{Íë†ûwa:ßQƲ/‡Õ¯÷+]ÎWߥq5‘TÕÕˆÁNÚXLÏNåžY|Í•&Fs8‹BS–F5ñe¨"Ž3Mc¶6óVHìm¦¤Ék‡%™ÀÙô·6¶Ì0Cc̺ `°U‹‹œzÜýè}Íâgüm/ÙõßÄç+—¨bzcÜ? ‡cNú%|ЄNßÖ°„iBÅV  ,8Ìž^ˆb×þ‚Ãû2fô âä‹ÐöüMƒoöé|Lk ¡²Œ1S¾ gY æä¥3ÄÙw_…ÕÝ©ý¬Ôz§vü”Kg°qÏšÇJÊïsÅ|1«" è(ÓÕ<©ûTõü,Çúé4ºåSœ*1Ad¡ù¢ûT»IOuÖ…ÁŽb7ôžKÛ;xÌÃíÝÓ[ãÚŽš<*ìÁÀ8LúÊß]IÈNzöÆŒØxÕÂÄñÿo5pn‹†×¥úV»èe›÷ñ¬†ðß!kË2BeŽkÎõ9˜¯z\-ÜUÐHo’€?5P—Àhˆ‰ù}Ïý¹Ìñ ÇìÛv¨¨Áгõ¶ùã"6É£NcÆ)ð»Z6]»æDtú>Å“‰Ë?ž“Çöµæ{ÔÌMž'›ýÎSÒhr_ô®Ä6W*uÌÁ[,¡þ¯—`úÈfŠR+,ö¹ì.Ä-R5sGÐåŠIó.}Ë@Ͼ?ÿ=ø·>Åd¤*UT)YËØ± `ºj»ÿvƒýùO•I«„DÖ9Ú"ˆÅU ‰=ŽF;ZwÌû_óÙçqຬ±¸îÊŒbÿ.þ³/Wa—‡Ç9DÚŸP–¦ ñÎPD®$-â¬HïÕ¦ €y*nÆ >Y!þÓã¾{7ÐX;žŽzï¡;OeA èÂAÕÅ‘°%B¦ûR•€€OFÔê±uã³-×Ö®ÖÏø`ç=Üë(ãøJ,çÈôºšœæÇ,ð§Kð.#²à1]/×ë´ý„ë˜%[«—[?fÄî;­`åº^‚{[¿Sq“"þÊ“ž¹uzˆM¹± 5& ® ò#L&*T „#p·^±›Ah9+Füˆ:9«ï¢8ÎHß.&aJf©ñYXïþ,æ"Þ‰ïÏ/;”ÏÉš}v€dzæb Ø1Š,ˆE qB†Ð¤$Bê~VG•rP¤U€{ú•Ah†€8âeE9ï³Ah E:Ÿ¹ó|?ÊÏ ÒÇYYªÈ[åõ;$ˆ³ì¬Oî'jÞ-xò©¾*Q ê ´¢jX£lK¸Ê±eß;³8{?ùT×\^A`]û^åœëÃ}æ"߉'MJ\ÜøPW6ÊBØ``jˆBÃ(D7p¨œÄêm£ M–z¹&Ϩâ{®äözF·ÌMfœµ³ìZ¡Q9ëœãË^¦¢'GªÃIæéø5Ý×]É»·'nÇ)£ D0eŠ®¿Ž¯]þ‡môì.*‚ˆ±}xg{öÀœÌ!Á„¤Ã)!§6ššÝ…Ï…yžo£ƃöïg[Ÿº|©½ÛÑå¦íi¯3[ä1YÕSª¥€½¼¨¿RÙI¹pÒ¸wD è†L"Å5m˜IL4fHd–ái eÊ gøÏK‰yr±.jo vI`Ù?€.?Gð :­ô‡óxoø>“&ėЃCªe™øU’B<ñÅâðÚÙöm7AÂÅHàò*Þçâê`ݱ´7’ ’9cm[é¸:g †F™!Œ+áad}¬Ó¯ƒ\ëËY$ÚZ9 5MÞ6ñ‹ãíK#ÈÊãÝÖfnͤge¬{3[e²wêÆÌb+ ÈÑ#qsv7»yÔU«9–9Õ+Úkq²sTƒá>æ„0mT„$v8Äò«Ï0-ïޜР7†Œþí»Úãœ9ˆÀŒÖ”ýðv’úGΈ&rEx³PÂXÐXjú« }˜2^÷w«®•.œL!C+g;”hmlª¶p–¡æÖ4ÿ€ú @ (ƒ/¤È˜½ q£a ²'¯h&ÆýÌžÃô(õyüGç>Çàú½K’„í ÄÄnN°iiËÏé/9gaÜycYäð÷h¹sUÒø­ÇÓA@ò„XÙýooÑUH«%TkÁæò'LÏ/í+ay $HkÕ¦ö«ËÓÜ+CTz’™´ñ¥ÃèoÛ¥ÒžŠ¶3Æm?Yþk·É›\ç<*iò‚©è¦g«w òjˆ”\öçéÛoó¾ìäë3}‰“¨ý¸QïÌ÷Hz-µ£t4OsöޝðY„ÓôDjÜ(æ·!ß¼\ϵržû&LO‹}@¬ÚýY;èÁÈv;-²‡µÌ§ÕÔ±.trkø~äS~YCÓó>-U ÉLùð÷8[…ñ·~3–û´~‡q›ì|S˜M’ §HÊŒuoÊ=~®gF$f‚AÄ´I™¿w£È½0ÒFáY€D (D [‹'Ì1'$dA]µ§†+~úý¯Ò“€õp9Îo²ó/ð^%*ð­WKÐVgz¸UàÙ±íôJ º‰Ñú׫ /„?‰œ˜¨weÞwst;Wùþ‰yï¼&Ñ“sb_K'7À¢(yÙâYò¥†Ì•‚T€ÁsÎ<5_ÞÍìn·Š£–åC£ á;Ä … ABP‚ZðA]HÅ¡lÇkñºØ·¾ýS’ÂÕ`›ÐM’Y&ÿ™>wáÒÛ8fs"1ï#HO8u­¯Ý¦I¹*î2}ûq—×Jë£âI¶wÏ×vlî§Ea¢ÿœl‰(ÿ£w`‘|â° "o‚ ëd Ü{¸~ÚÓeÃi‹ÂdXéGGj¡ò÷Ze?Ûöú'\Åíý/­ºÌ?:ê²›NrIöÑ*Üz×zmÝ4 få¿z0@ÙÜzïWÍ£àÄ=<=lC¥óÞϪ6Æô]5úZ /µÊBPbãËr:•¹”Ê‘fC¨°1T@€&8šìó¿Q|ü4{¼²™ïÊÂS¨9–Þý2šŽ%%Ö¹šlûõ<Èöè:?)±ñ Íš³þŒüÏ}ò^Qü*?“.Ex®(—åP)ðUœŠ.ã'Ò.Æ4L¨Œˆ’H£ºG>f@§öUÆÚ ÒQˆ|Bü¼cHÉHJŒ#MŽD¶‚u2„ ¨ÀÃÏ] û”Trj Í J@Ì0~öþBŠ<ãwd¹6é&îóÏÑ}]è’8(I@ƒŠ³HM‚M ØØ¶4jÆÚzã·-b×4[\ÚÜÚæµ‹Zåk\©*ÑmµEÝÖÆÑ«*ý{^Ï7XÏô§PÿÀ¼säjgþ””Fäøð´lR¼Ãm»*‡Áªb¦•²ó¹¹8›X¨žúŒ;¯ƒÄÿ«½;VçÕkÅM@´.šTfXn,ŠÚ"ïÓ¶ü™ ùq]1O‘Kf׿bÁ¿ä¡£D¸SWTo*Ì@þI÷CŽRŠväéΪ¤Z’m(”‹„0²ñÓ2÷82mq… u²ÂÚ§;¨·i¨ø×Ù<샾=j¼U½-Í[¦5Q®mr«ì¹µñ±mrѬUÌlZ‹\å¹Í\ÑwvÕwv·KmÍÑk–Ü«˜ÛtÚæÕËb«›k•2RdX)H,ïÈl;LÊêÂÎyο­zkÓäÞ'í~WË™z’Ièq×ËEg½Â*Â242C=.€5^7Õ§ÚæÞÚ‹Ä»‰(bÈUGÐe‡?ßmX³†Ì«J­úeº©ª¯%àÙ±÷%ö‡ë÷5t=<‘UÊŒkŨ*ܵÙsm|óû”½&jò›Ó^1¯¯×.’fÞ7F"ÁN`dQŸÙ˜.xБ1¸éï{ÃûyÓ,äúþ_óÛÝùÿÛØˆÅûnÎŽ·ÓwÜÏu¢ ¼ùû×%ív;ï—­Úà 0à 0à 0à 0Ã@˜‚ÓåűL·¬óG϶Ü{¯{óΑ m ¯{ò@ôŸUC壳àá«Ý|÷´Ï‘r¼™‚‡Ž vû¦÷°Gy/ÏnA†ñÜjw7·ìˆzøáÈjŠÖÚÚæÙjÕasUÚ øè­ªë¢„ÂDl¶ÉUW@.§ñ®×³‚mŒË›LÏä•*Ä(ÅÈd¨6lÂLÓô;s^›¾l¦CHY½~E„–&.?j? ùqâR.³̈ŠmȳzÎÆ¹¤´šúÝ•ÙÀ¹Å„¼òˆûÄ/ÌQùéïúõvþ³ºÀ þ43G;(Ê…kQ ™…&{fì¼öÜÊßÒgü­¸ÆZx¼õ«¡üh}£+^£ë±®¬’»Vúøt#:NVCñþ³:ü=Ãwþ‰AÜà‰ÕÞ÷ÿ€öˆ_À+bßœ4…©áH§QF`# Ä`¾²J†ªhä(T›2{⛑µåjÖh¹µ¯ªT ™•=DŠ¿f:Pýo«ÉxU±ønQj…M o¼jÅ$KR•´ílÚ–HH$¤v²käÔÂò¼âÆ8’•z(+IJ XövŠæ>é±t§"„ß!†ñLòÇ+¥Ç©®Ë…] Ï71yA²Á«›ÈP>¢› ´ºÖ÷qžÛ®š/Èƈ13ƦÖÀ§…-v /¥­&/ϧ12V%ú@^7ýug¿n°Ý‚͉&îÊnaÆe§C=Sf0T­3Ó.¤&·Á«ôÜY°ìÇ¿—ƒÄ +yº MmÞ]ÔW_Æíå•üîäÙšMþ¸Î® X‚´œ—óÄßÑIœ“Ònøz _X\DZÜìÛVÕø©Úîžù,ˆìSeвd)3]¸a`êpÑèfÙ¾]r ÁèsCM<ÊŒhß²Ò%·{ÀÓ°35“>8˜í?škš8NWck+:É£5¨ïèœñ‡ì²`Æa‘èí±:½Õ©òß•¾P¸ù7Rp¾S»™÷1oÀߟÿŒé‰øßï··Á¸ŸfiúK‰Æñí•^ïIl熹/I…éJ#!Åæ%$ˆ£®&ͤM:x† `ÑT•÷o2C˜óÔf*‘RY:U±6Ô•É@Ó¤È*~;î¼M!õyƒf”°îºû…Ç' ý/¬Ï¤wÇ&Aú Yâu×ÇØñá¬Ø_f»JN¹Ñêê·Æ°vð køŠjÓ×7žÚfÛ æÙÍ™.‹ô™‰»ÎöÊePLƒ’í÷÷¼DV>IJÂØæ Aì’ƒpö|&û™Ã$à¦eîNý«éÜØ ë¥|Œ§+*½A¼®[œ àiž]ì<°í•¸`–Z4ÎÁÙÀ¸Î'¡v¤YøåSç7†­åÜÄX1paÞ‹œ5ÝÃIk…dçD?€ìGi¯,Ã.×å§U‹–ek9Ýúã̆êúÜ9¶Í˜Áb£´húTwÏ|ö†ˆN#o®ßœé±‰©n#ÉñsÉ©wµ‡x*ÎÕ[qñåÈ“ec]±]7&¡OMwÇU½TŽ¢ÍïöõúÿG?ÇÒvöú<ÏŸ³î‹á Ò>Šã}ùö~(¯ìš÷Oºß­ óÙ@Öê&ƒqù½Çéƒóñð-qïorC͉µ¾Ž ƒwöùxXŠÍPèÓÝ‚!{žD=Lèa9ú_l>YÍö#C·<›»[áRÐ[\ÿ+-Ãhã2î3¹ñY?{—÷-Óˆ{/ÑÎ-cÊò chp­ãÕí—ÔŒGÕºcÊá(”„¯± âb#h"X]:Ž±êˆ¡P%˜˜Ûä SËûíæ=Ôî…w_AÏØ•˜þ¯ê~»žß.ÝìÎ}3—ɶz_ £0^Ä–6äŽqŠr'‡O;8ÎÖö¯\£‰D'ð~WØû'ŠgûÓ¨Þ¥š ¢”ÖÝcß×0;Ýã]ýtß{#åö«\ÛÖêäß×Uï¶v\ Œîq\7e̤¹$Ó¹ËZ='k;ç6uúz¯kŸ¿Ùâú_ß =Xü¹g/7lu{Äüë`M‡Ö\€Åàð~fÈç-‚,»G¬_ ~Oï"ª–5àU|~üqïª?ð»a ~Ýå@cŸ‘“‡8Oç¬QÍ)´  ÝÑ4f‡kiÏ—V¸àv¶uôûv¡{6 ²è¢úXü’‚ŸÊrà£k|K‚ÍXîlŽ™·C„úIÿ‘ê3\lªÜD=ôŸƒÕÁI¼Å=öïTé!îû¾ßÓZü.¦¶ÞrÅ!›Sm•-fH ÛE¶mµj"Á©HQMwWUÚDÍÖÃ,f”EŠ*ØššZŒi²–¤F;v­•®v®éÛi•·+]!@‚HHÔ¨(VʲY ?aû `õºtŽóâ‡ö5õÂ÷x8áïsÎðˆ„•

jE ZâÃÏy­s\Õ˜ÖàN¨iÖ7äžZ£dDzd:‘;&ñºFŸcÈß?ý îòíˆælµWmU§^éDâiuRAWJ©5Xáͼô\Aûîæü{®ð"¾UEœ…ÐqŠzWˆ,2n¨A0†‹Ë!ŽÒ¾É­ÁÔ±7ŠAdNG¨‡‚dÙvkÑ>Ÿ—ÌvôϼÄUc;­"¼¨P÷« ‡®Û¦]ÕÒ#qv¹^®·¹Ú¦ËyMê‹$"p[..àÓ iž^´ ¶»;e o0{ü‘vXÚm%â®åÓÈ«1˜à(¸g^¨¶,UÂIl#TIw‹!N¼mëÎ^h *æ¾Õ÷ ½5=ööÛ›ÛÒåú½*ôÆ´[cYØ„CÅÜ—­óëØö}®Ì_+àyJSâ8”?Í{íîfª-5‘G6xΊÚ;ìB°¢êûw2¥Z6P•èÓêjÎí"dA'ŠÂ£Äv:Náz\‡ˆ\<ç)Óè¯"Ø kÀÒlz$Õ ª £b-oä9HT‘SyZÙ¤v²A.·íAA4˜mîùÏFºû{¾LéäôwtµIÛªQÑAÑÖæ=ÚC®Î¶Îtâëü÷œâxt4vM}Ú«ÄØc üý #†/§]¼ubËÉòà;¦ñ×Õ ë¦[]qu~c,qñ%q1|C’Éܱ££™š8Ëæ­Ñy^S&—K€¢Pp€ÊÍ€ÀVeÜba:q›²@»Š‡éB *D+ò™Iù(¡hÔ3Ó0¿±ˆ‚ó vy‚”µ©ªk+)@,ZÀb¦ÙÔg¶Ô­DùâÆ S!²µ²´l»I”†N Y;!F8Ô=°æ›»¤UTÉ×é–H§2!w±E¯XLi¡UE“ó–Ó¼@L(É£xÞpˆ…2,é°×À–D/E D¿ÂÄ@4-Á7!¾àƒé©ë¤êoPÎYY#±5d> Š×ÙåæH°€MH¸a"G+èÏ)Èåx- z ü=&Á¶Ç©Ëß.ή2ïy÷zà|²Á·ù`?vl8KËÞÐ)¦Öß(™ønðó9u¢••lìíêóœÀq ¥ÂÊž@³¼É§V3îø\}O_Ño.·uÏ—CÁ÷èàoŠæ?BHš*RÊuAšáó<’¡™|,!sf„‹˜éhÉqÎTÞD ªb6úàжN·ç·/ùž; #ÐúøF3ÓÅ¡ãÇy¶G§Z»²^!œ¸kó7£ÂP”g¸±™út ÁÃÊÑЫƒ|o = úiëeæÒsãà$€LÁ)S{­šÑ÷œ“• ¦™BÔØ‡Ž10r1g,¤×G-píê–Ìù+É*lÙ³%½2¹jó ‰÷QŸ_ ŧC•1 ³%±á*i4¾`xÉÉnçN­Õ³±´ÙÂ4†Ûž„¶C^ÈR:‰si±ÒÝ=êò…¶eŠ%8ÝDWª£ªƒà A\ЈB)œ†Úá¢v%íÔÙ6›[ 8Ó=Ç«»fPÑNÌå}Ÿe¯Fd½˜ùŸ ß½Y!¿Eg)a{|~›qÕÇÇÖ×ËÞ¼‘Ç'»˜ÂúnCËc}·V ö|/5æ›ß¿È÷=Ízº{™]~çF£¯UškÖå»L²¬Lèš°M$¨¯³-Dbïx¼üé±ôB6nÊÜGÙZ¾¨'#é¤Ï”îáµ6øý¯§b±žLµ„,Æ=‚¬®>X«¿Ô%ù }ƒùçàÇèxÐnü8 È1ÝYŸÝ'¢š`s¹Ãá¾d|¾D-@‰5‘™S€ª–¡Ë"Eq`‚Mí–Lqµ¥ù“‰q¢hQhžÚ6Q?:·Ÿ¤Ôa¦íñùS´Cü¾Ð¾Vœ–ÍÓB*é:\örâèI’äL'.c‰É@hû!Ÿ(EÕ¥Ú=R'ï,#}  :”}ÿdLõ”ÇY±'=8Ü;&oWÎ*ºßàÅdcøí{dØžd1dpݰ=Üz¿Ü5%¯vÀϋ媷9Œ÷v²J‹éšpÉ™JŸp€Ò“¥[ quBcoQ˜ÈöDª866éåõ0+Œì90!$ÌÃ&¾òhuÅe§'°Ä¶Üc8#C†±z(ê]£²‘½Óh*—~=aù›÷°ÀbHü UÍô“gdŸH1·ðÈ[îóÍDß ÈfÍ8 6•,-$4  ?»ôª„}2MÖ±#k@Ý<>#àc ¼Å­D·¡‚¾EZ3]dq¶ØÀÑ}hš.ׯ‹5ºõ¼nc9a†Hº5*îæ^Ù=ˆàÞe7õ£ù±¾ _‹q–‹f Ž‚kóš£Ñ`u–—Çm¹±³6f÷ü­ÌÒBå¾ 8-ò¥Œu“úñô}uÛ Þ =?ÕË=_휳“ï^'iˆ†{Ýüý»ènÐqówÐ-<à`vïÆþµ;†Iâ[ˆ†ìl`Tºˆh\ŠÁ-eŠfmá|ò±. —‚É‚“‹¾Kë\–c[§Û†—•ºw;ÓwµÍ¶RŠ{Z2²F-…JÄÊ釟vz°ÓŸèØßã¼èÛÜ} Dzf6'i;Ól·YÍàkÆ|‰õU…ÝX߃UvtºöOy *ÉÒ4]1NìŨ»D8g´]»à˜‰¢Ê l¹a nqãXÜßidájÝÆö#“Gtg’£é#æEµ >† Z:b¤± †CÀ”<úL÷ïŽì‹¢ELÎbö»†Iø!‡Þé@ñô+ sîȯ—¶† ß±<EŸÜâg1þ"À£~|çOŸn3¡‡³«Le" ÀÍ@ïc±{.lè$ë=ÂsåÂ${»!‹È 8꛺PnŠv{•ÈFÙâµÝxµ†0Ó:šr;#Ûçø]k‘j kd2b˜¿¤9ã-œ:WóƒC¶ö1¬N„ñ‘N]¢ÛTn¿Ô1 ã ô5ËßÉÄ |òµ9¹ ?µ.­‘~7e´+ôn×b–.öâŸ!å¸ ,e–¶/UÄs·ÛŒ:¾7rg*Œn圦w¯±^:òÂi˜nÏŽ oÍg…‹ëNèlA/û9Ôy˜Ýó|ñ•! fPDVMÆß†:¾µ³ªFþíj01Âg;=ÈØ(ÙŒÓCÛ€¶áP6È•f.æáq<åæÓî÷Ú‡µŒFÙêo`Æ•ëM˜À§ü¦G_wÒWxÔÕû{†9°5nš÷#9äöÝä_×"„{ÂazD-.½—¤)þQG^8íòÒnÍkgñãpH^Ž‹Û·T'Ö/‹Ž}í^(t[ë–¹h(bUn³ý+§ 7Pb!ÉE®šŒq7ÈFÁ©N9Êa²Q}µÁÅZæí§_Õ]¦¸›^n?¿Ìe^áÆXöÓ]Lí£ÛüÖ—‹ö½í¸›M—¿‘ƒú>̾nâçâÏvkC« 9Ý —3ƈlbÃämaVcÕå“þ?Ä þ0[»ý@Ù¾ïrJîÃÕÛðOcØ}=™¼.‡„£CÁüú‚Aff¥&Ûû>‹­i2~ K16¾Öu«#cÑt9½ h‚ ØÛ ×BýÇ;nÇC¯…°äö7"Ûgqòç¾y¥ôãYÈ> N5o$cRNƒÝƒß³‰c<ãÓU:¶>GÐE ®)ˆ}‚,;%X7­Ш± 4$i«M3™ó`™&Œß]:Öûâ£z. 3ÀÝÏIÁä¡ØÌªõY¶ôBô×½ë÷]B)eg:€‹}r€~R¸\¯\"Öô\Æ{A˜îÙf%œÑ·œ ¤ÞX\µŒ Õ?jFÙ•ÃTˆÔ…Þ|“ž™±ñkS—µ¯Ï;¦É×x-u½äÑt&í’)"‚+3JšÔ¨ Ãjþ7jO#ß<.¿7…Û©Òu²¼Œó|õÓiéàzœcžŽžÍì>(Æ3Š\Ž>°èys)а"8ü+sW ¦–. ÙGÔ…½*°÷ †aÏ– m×»´·ÚõðR$˜ÄxH=ðѹ¸UqûžEÅãÙÑ'EáÂD0:,SfdÖÃ1-å‘!’ÂÛ[w²Ïn»aFL˜(GÿÆg%øV“`NÇ„ýDñ;jŠ$¹kĆ me¿¯ßùDþÆG›ÜõÝé/*ƒ÷B^È»6 øÊdÞš/ ¦ÛAÁ± .ø ’Ùá݈tצaòòXO\Á“l;5ƒ6lˆf„š_ˆfËivcšø3ÏëëýÎ7cííÏÎÝ8Ý­érF$0•ê)¯Y1L£J€ w) ϧ”Õ V£ò>´¹Õ—¥Ã_Rƒü+ÀÏr¾k3·W44ƒT„¹Ò D°ÅÀ(Å0·Õ…í‹°D’IPÜîְôíO@ÌF&*±™z?LN¹Ö®î̤yû{üµoNÉØ.½ avï+ ­L+´áS³ •ð7;…ñ3ïC%3{ŸÛX8\3J¸~nÞûuíêöžón.áÏ/L)ºÍźە¾‘›½[AG‡–ìFV°$“ßÒ‡. SL@wçSkßÄGPËÌtË]ßµ\õ{Ÿ.!ƒªV.÷Cë2Ga…7¦@¼ë«¼ =IxHùJÐ ý_‹¸©ùa@õe¦r zh·D}Wµ~ÌNËô² üµÅ/ñ×R ®³öPË„ü+M §uh&U€âyoS83ãȆ{¯UÃ<2L°‘ ´VC„™ Á;»×߆á=!Œ"1Ry„‰UmJ×¹I¶UÈÁ¬ªÅðå`´„XÀ‡Pþ³IerÂjìö8ŠJÃb𼡉Hf Ç-¬%£©Ý3/_Õæ1ƒÇæ¤{“”8[!ìÜà0Hbö¦]œñ-z*mòcù^l`26?KŰöl{ës\54Îi†p$“vZDs}v´Èîêq#ûSàMö殞µã– Qäý}|ãȬ¬´°Bü(kÃ?iv¼,a¥â1USl7vÊ”5›8€_†Ž¢úÖÛ{‹è1ÊcÙ³îR W7¢ÆÜ‡èU¾A ÇÊÃ&å<ŸqeOÈI¦Ì.B¹r ÜØ;Šü̳ϕzèÉÁÌ^ã³];ÈdSŒ‘ͶÈq•~oPðDÙ Ä­þlKèŒ>a½5Ò³›‘k™‚Tù~aE¯±4äÈm~81õ{©¯à·°Ä@$ußGªBH®}G¨ÜËË`loͽ3™~ÞXÖõâSàК‰XLñ ür»ˆA{Â_iaråòsýEÆ)Ä·É75lá8vs¶ez…É e¶Ã3ƒÃF3Qœ¯Bü!…UÚÂÏe·´˜u‰.# Ä5”ï)FÃ-©!öÖ4\'I"2„AÙ©ÕJ†–FtIÊaD÷!è„æ ‚!è³%£e¹¶‹‚TÓˆtˆtb×—¸œ¦ZÊЬТów·® )plôd°;™§™83­+¶ÊRH8ë*Žqµñ–ñÃǬ>ˆ8øYFbNxÞ^ž÷9.áÉñ>ü8'+-Õ÷ìPuvm$ô^œu2Ê-,¸.{20¨ŽÓäÔý’†µ/0;†•ƒRe…˜Új^!¸f$™NHfÕ9eŒ›6LkÉ€ÉX£ǶsÅßåƒlx¾ƒ¦ãýº½þÿ;.ÎYú·ëíÞMÆUëÓÈl€oÏxöÄÊׂq  •¦€\dzPê­l"$Û¿Ï'|ñX°÷[ìº~cÏ6ƒ°'>„{¹DƒÚÍבéX/èx”!;¿Š4À››› ¬@Ùɳ‘=Yô¼ÊÁ«Z‰ žÆð¶ÊvÆd2ÊÕ&‚Ë5I",Í1½_ÒÞ€K[…`Þò5‹|]ùew£p:÷©…jcË[mvѲ/Á¦ÒíZ™¥ÂÚwYö¬ìªäeèC«ñ¸§DP¥l3Å’+ÌÝÝ4µ÷™ö”Øé?K8š”»Èo(zº¡L›fÁeå¦,ŸóJ .’ž uàvñ Ô 0»8sÁBRëºõy¯HôÒ"ö¬²·Uú"ÞŤOKÍã‰`èg¬ô>V¦”<¤Ak0nÚZóݪ[ƒàŒ]²æ§¼ÅéÊEƒXUñ2 Ú§œ Ø‘ ƒ¤Î»sU1¨Ó¨HÈj±+’b=ˆˆ“’êŽx¦ryÂÌKŠæâ„‹åTEìø‰2èsš›žÔ9•¼p“ž²>³šEö÷düd0ÉÓ¡h#béÌ'eHÄ‚À’E`Aˆá¾ÿžh’Çym¹éÉ6”Ö1ëòÏ—Ûî†]2GÅ 8÷6ýÏE‚ Ë·?ì£üGº¥É°&}ñ‡¹èÚÀ›dØŽez ÞÚŸªVíó·âŽ:n%X@°í=Å(Šk5ÓÉË;Îzvn]ÃüÎô óö&6·‚1…­N,|®MšNÙqL Û©Ô")¬3kpq‡Ì_Š|«½f!8Ì̾HÕò!½ÓD7¡>ÖB›Ó4ëî¤N»,ñ-ÛŽª®oôrù¶zª,Ô Ìu %¤µ5s"Cü{|‡iãðuk0!‡Lݵön}*zx èß²œ(!ƒº¿‡†I,‚~Õ+-ëŒ\hääkŸe\Á°Eíå¿”üo¯5Û+mtçÝ®zò²¬.@îG]Ð%‚+ë5;õf¼wvd’î¬ÍÑ`²_½ÁhAr©Ê¸5á\éñY‹âq’ÏR™ å¼þ¾nL„lNR³2Á)Ã<¸¾pÇ Ýí¤©< c‹úlÝǽ¿(VÍ>uywäQ½Ú‡6×6{^ž§F;Ïн_V©ÅЪÊVï`ž¶örLÐüëW~õQ»¸OÁ+uR˜wA«áÒãyÄ ,úg7V"êˆcÙYù,õºáÕ¼:^»QX‡×ìÉ­å­¸^¿VçÔDÚªç¦ îm|nae5ÚoõcOŠB.ƒ39a‚yy7¼4^MÄ0Š*¥.+MWœC¥›ßÂäÏ0pÙsL &y}UÎÌ‘†.ÁÛ½ÏM;}² nl…Ihlˆª¸Þ1‚.¾“ŒÆn¨Ž`Tée'áÄÃ?ÑÂæuŠ<‘RóQ8ƈÁöøÝLjûZÓæ¯œMw©£{´Š¹ÕFà äIºmi1zcHEÿù¸ç½Xjã,^*]5Ä„$yLÄɹ¥@¶<ÓØÝJS ×X0ל²gç#ùM{“Œ—˜vÍÛ.Ïbž"¦˜Ö(% Ù¯$<>EÀw·"r#€n|U_'Nf]Yt¬×¢Ì3~ ÁX‡©uW» K@vÍê \,ÒL×1kZÔ_½õæšÊí~²á˜Š,[DKà&fwno.aaÛˆÀz}hb\Õë‚Ïd è63t!»îZñféÆ{ušº‹µÆ1,áù1^‚Ë«ž/Ív6©Ñ WÌY¢ŸÏ(mŽ*èã&Í ÐVn5|óu“ ÌQ¬ªv‡$qã5Ã*Î"A‡(I,n² ºŽ!ÄHv[ ¹V4T ›|^4­Àåúj…Ä0>±,>×ÚW·ž“Ÿ49r[–³€K`©=؆`ÂKJϱ@’G¦iã5ýå[,ä,§>ÞéÊÓhR•úI>Nˆ¥9!î”옙âc Øÿ–ïlš‘ö‡RÙl½lEÁÅ ÷4á@å–0pÌEµÔf˜iI w-z”ì³¼=µ ¦á¸AšsMRuUŠŠ]šì•AûëyD™Åœ³b×dN"J77 Å“l°kÊ8V¢ñÊ5žÜJÆp-(Q–¼0À‚FwÒÈ7!i}ÇgÞ4TƒÅቯ˜;”6lõfÂ¥eŽZH1Bß®v·³ÜmUÒ*!‚ï<4]Ùù¦HÅ8&÷F‘Œ¶'8°¶A°¶Ol]òÌÐÉ¢Œd<æ˜b}h®û¨¹­•mD5ûSŠˆ!ÈÙÍ× t¬0Ï‹H$¯'ô7#¬6JrǺæîÙcÙ¸ÈH#å-ïÙâ7«Ú­èB$¸I?ÄžøW@Žš×†BæçÚå<äØÛ“aŠâÓ›gÐ9ÂpD@A³ÞÝÿ=Ÿáuò;Úê7°åt©9±µ…ÞñAèÑaYŠ 9À  '„,²P&“/˜g|!«HÙ÷Qz{h(¸±b¶è\dƒÀSÉd}0¬·ˆ™-~oOžIA`cì " ˜>âцÞo"tÝè•1³nåΟM¬\¶ \m³=ØA<Gí÷Ä=8L¤ZB‘Gšî0%±ºÊD Žæ#7‡yšìâx¾aØ –Ûþ¥^(³(§v_ d[D+Q±gž#x2#¼\ì:˜Á¬oÃÈÉÛŒ?cÿ=O*j¯ãÛ·;­ÍÉÃ# uë|‰álœù¢þ Ä+4^ïBÜÄÕÂT|›7q“{^ìÏ!‰—¶ˆìý±‡ÅÈ€ü³žt>V·Èz'æÿO™ü.mïXù¼ÿbÍuyŸx¢®8S‰ð¸k­}I’ùfÛîÊ—'`ƒó@NìÙœá ³|ùé%<{39½hÇQ:»}É·qºzó£,M•æ4)L;èÙs®^Ú*Nɦ©§žæv`ÍÙšëÒ\Å  Šg¼Ï?X›[°mž€ö(ãùŽ…QDQˆ_ÌMŽÇ^»·ç;¾É”qä†ÕwÄDŠè¦fÀ®VÛ ³£s®›>¦+;*·ÂÜ+.±””%²Ødã“d²bŒ@Øe\Åh–¶Ì¹ãá¾Ûêè†0ÚЙpÚ»Ýml»zs\%šˆ¦‡– Ì¢E*’% ­¥ª ‚{¯‡¸¬èã0èý'àý£w•Û²øþ„lOÈõúÐþ|¨‰ø·2ÙFASP_~x)6…Uõzˆo"­5´æË¤*Þhr¨0M¢`~„—Å•)°Sz„0ÇEk¦)”Lê,’Ø«ëë^£JÆ›ùúø¯ž}W ÷ùqõrú)ðß:ó=¢«”ßV=óð#¼{ï¾ÙÒíáÁ×#èëBËz˜ö¯Q½ò½Rn#]—Çô¯ô¿?™ù-‘ì~+Û¾{%$Ê?G£ˆøãÚ²|S´žÍVQF!É0‚²›Ñ¹vIIgä¿ßL5˜Íï4ž3è°AR',ÂêÙm°fËzÎß{»ÃTÿ‡¦—±F·Ó§~yÓJ7€¥VÈë"Åæ"í Ÿ¿×çW®î;ø×}ĺmóÏPæCÇsw³c€\¾Á¸u”ÌJží‘¹©°•ïU©p‘.T5àôœã«Þ`^ˆÄ¸Üo0I¬] #Ë‚DŠAñužË"9ºq|<[3\ˆ3Àˆ‘‚†pFXÞ¯J3!ڔɮIª0â¿ ï/CB±Í“dÐhà5Fõ©¶Fæ¸K¶ZîpËï-ÕèùÇÌ]“Y¡œQpšdz¤óÁ*¥Õ·qwE§°éhEw±1> dbë¸acH¦²ž¦73@Žƒ¬;NÝÓW9é~s~“÷«­wÉd€ªlêq â_¿Ô L)TŠ€…P© (°ê·×™S„ªÐI…ý/Ý<ü› µ*pâ•=]xÔ´Ê$à„°õ×ÓÇð˜ˆÑ n8£‡ ‰½€nX ÃCIl«wøP5v»®éØ2hݹ·S~C„PyG'ÅùÎ=v¾W`ô˜ßg—y[iXòïQúbônß«yÌÁ×ë¾à}"^aîÜ~¤»T¿ªapÊsU§ ÙT/ˆxýÄ¿f jn§²Ê6;]|x—¹ùfä;ÁáÓ‡f#ðo‘z4IXý§¨TaG”΀~Ó¶ ,‡w\ÙÎb\'’ß´¨8)nB ’jk/Ô˜ÙÍŒ¤9dK]™Ñ{/Ôf)¨¦LZìïé/éÞ§7ª~RÇÎ{\FòEðô•í7…©Ö 1IôT†[0êò…ÜCðÆÓ óA;ù÷­ÎÎøÅW/û¿KñŒ‰ú™œ]û¸t8kóÅWíÔ$:âÚ±¢2Ye‰Ö®×9Çsmë¯Tñ„·©É2´Ø·–Ĭª3Íùgóס—¥šá¡´ŒOhÞ%¬ýò±€[ëΰ\ÑnVâ,×»ëÑÅÒÖ^Yùà_g˜å‡»,m“àUYqä5ÝRZÞZ>~Þž{ölgŸ'™E!¯fhÞïXªñÄê÷îwtÇŠúç0Aq ¥õjóqÔv¡ói|aôε˚À‡žûcpü:3{¶´îü6N¯–¾ñÞ!ž=××ÄìsW^sž)®ƒx®½ÔüzcÆ\ÈÇÒúêW.i?ˆW‰^[·Q ¦S׈ ™ãƤ«àÚçÎ/p\ÈíÖüsq‡Ñ‡qÍß%í¥SŽÓεÚ)mÆ4s«ËçxõÇ9ÏgƳԱ;nÉÝiÝø¼‡i=°ÑÄ^¥‚¥ÝgM~gÜ×m±á?)1¬Ï »Ë"†wVääweÞšOÝ™óBc3Áx鳌`Qck雓:M—{Çžèl‰Êd«d@áðqxªO}ã3Œ‹‘¬¬TÍÞ6­6ê½²(#Š{F%®Q9îì:êXm³¼>ÏWlä×êMïßæ®ñOXÝw¿yx\—– »t¾MÂÅä2uÛ³aš"fí¹CƒgÓ=Åe<÷Î'1m_¾Æóç;ðÜeÇwÕeFÄ&õËë2ÃŒ» QõÔN§¼†‰À‰Ü+ÓÅï^»,å«wœ5ÅÈN‚øaÛwRço&Ï“¼Ÿ¬Žø¿ž2%vÚšœ¦÷s8¢§ÓIý{g_OytrEð÷—Ëæüñx~ÄB»ë·ÆïÕ,®çD8ŸYÑ¡ã‹æj£>sWói±}¾ññúZ-òq¶Ÿ•í.A??îÁ1&¯~Þ÷Ô4DFí²·úf!ÎxPÄ;¹drYëv¦XÄsêS:ö²v¼îÚy]‡f¶ÈÓ±¯¿¾vÝÝ©²GÀk„ù|ýDVGÞ½½„zXîûæ[ø |ߪƒ¨]üÝo0¸–,g»‹‘rÌsèÐ'’GaCvçVNL^ïQêÃîa<'°àúm ¼û«H"lùÈm¦e¯4LzÓZ€¤mhnSØÁŒAÓǵÆ6-шlV(ÚQ—l­„l}"LÒ¬¡‹ˆ×g;{øóç‡Þþ¾þ^ãÎ>žÑ³·›O¬¥­»ìpvXÛBîܹ¢X¼î¼ä¿ó×nz›®#uY$j4`ÆÐÆ ÂÉŽ&Öaqj쾎ÈùòcÇi{û]üŸuÂøÊÂú`kéx„øÄqê~3Žü¶HŒRmD¶íˆ:1]Ù½—gÓ_œ«gaÚkE óMK%‚éØS°"dZŽŠdäËöv!˶“–?ÆìÎã4ÕÞÌÁX[úž@~HÎúqüë·5N¿’Îq̇Äìöð"7¨µÞÞ;òœvæð´ÄÁŒê¿é,¶ó,n§j˜|n¾"Ü À·È³é¬$g{­ Çbô0Vî³k=¯Ð@ ˜À·åp,?”:qj6±"þÔ³öw¿µo{G³Úw=îf<ôV‚æ(ÃÜ8â ïëÄ6RúšÃ%tóqÕ"ÐÕÒS„±uÂLj„Ѽî»F!ußu ¾µÏ&øÛ_6qµ¬ä<“Ñɵ‰Å›¨£íz]M“¼6c-zÚmÆý;YçÆ’JŠE ¢Á`ЬÐF£B¼²ðç׬]à1ƒcK¦¶#ʹ>vä4ÐØi‚u·2u’¶bõäëW òsÕ•Œ¤`²) %5æç½»6é±ÛúIV±½ 2>M†uá­aɵ‡ hÕ0…,±ÎȺßNíTާ6áÈ0€Ó@s‹á—û¶†NþÉö|£îøÔ Jª;Z€S¾IË$5# ªòב€<i€©8Q™&ÒØÉ\LuŒ$U*¤di (” ÙŸ±ú=Í›=Ÿ[×sþÎðôâ æÛÎ_.•…iÀ)Sz¹ L©D C‹@N¿[ÜÛ¬ˆvV¸•ë®^pÇ:lc·wn]\ÚíÍÅ;¹ws!÷–­~ŸÚ¤úvßxÖÛmbÌM±¯ÆÊùH†×—Ó¯Åäû9“hM€ŸæÊÁb(RÚTXÛŽÛK-cddÚ…ƒÈ®ÏªËè¼]:rãÇÀüûÃðØ´/çüö¢÷ þ¥Ç긋”†»ÉÒO†¯Ö‡Ú†„G³&í‡<úð­ZTÁ›86N–ݦ­É¨†8ýœãœc ‚ñv–džfÌd¶5SV¦–÷aÛá àŒ>)Ô;:ì?xúñvè­3s}4è¦HtmûR$1·/”Ô»KãlöÍÅþ7ýÜ 9ÖrÍKs5Á²®Ä®è*‹¦6™”Zbi¡“5ë‚׋õ4dîc~XñâumÊÇ´gŠÁì¯ßŸuÐdž*#ç˜4;ÐÊî÷”ôH†ýÉŒÿœ×E©ƒ¬Êj,{¿#"›ð[ü²_ÚP£Li dOc+Qž¯£ä?ªòµ^æ–«¯8¿wÌØH¢DëBü˜à |«T8§hÛá_“Öô<‡ Åy]^í#Ú¿³<ï“ÅÉJEä ù?СåÉÌ‘<á `ó}YO¼Ó†úM®»oGò³KËéõVRq)ñï=ÔÒÀu?ÞoøòeKÀ[2üÛõÕB"_Š\º%ªÓæ!oUڧħ¯#9Üò‚馅 5QñshïE]æãîf¶°‡mÃÌ!!#£ìe ™ýb¶áEøPùeûl+±…à(!Â"ȪÝb7_ßõ·]Ÿøfkzí3{=ß=‰¹Lc €`f½¡.˜æãSä&ócå¿ã^ÏFî/ýþ¹>?Uþo·l(›’HH‡9?i4‰×6¶³íyNwßÈçúo£Eøýùþ g[{Íßüª¯¿¹ÑÑÕÝMBx.ú1ï'ú~<—ƒÜoÝåkèKržm&·û¼„@ƒË ÇkãËå9!ùžVÒ9¯·}¼BÑ-÷½m&ç¢ø?—qèu^œúÃܘ£E" ß±Q^Õ: 7Ÿæ†µŽDAñÞǹb¸ü³M¶ø±‹ñ l—­à¾o][ù^}Ö°^G[5+Ý –03;«ŽÏvÔx_ÎÛÊÏx]—xÿ§>ÿŽí*< »’Šß‰¬¿ª+ý‚éµ ïæ¹/O䲿®ý®3MÒë1ì¡1fïJ¨NÊJø ÿ·Ó“Ö3¨íp¯ű±€Ñû íu4—pN—wS{Ùt,•µä=9ïÛãÃEîp«ÉxÃyÝn™Î¾ÙÜ…õþþoØë}Ïۨз«ÜCXµ¾–4ilÙéV@v›ØÍJÃÎë&6f³íüp—ì@Éþˆ¯¥fÑû’srefUö oÔ9&jqÛ‡¹íþÚí#‡ÔÛó~9ñ‹äÅו4çªÚÃcé¼aÑ€!Û™õÕ§¨„A$‚HÇnÞ“2ó‡ÇÁbo¯$\á:#V«kön®=ûX<ÝgŸùÕAçjóÒý®{göEò:Þnnr)çÞ›ó}©Üxc^õãüÍËßw¸Â[õŽTë6½•‡“àü|Te(‰˜Cç0+|%E>F%¾1;0e(þOðc=ÏÕ©â ¼ê§ #¢èìóYqoÍ(("²úÜáÜøgu~´í:ioЃ‘}¬­Sú}¬„`©Í/ “NhÒª^!ì“*£™Îÿ;÷íóì»scä[àe¼½z€@Ìäš%%BˆT¦óÉå`÷áþv/g›èÿâxÛ»–{))–ÃVw/À~Æ|—UÂ2>§oyªîWz“N—Ú\QÀ Ê É>'9#ccY&TƼzn!D0 Ud£ZU* "L©ÐزIþœ¬K ½÷ÛøŽÿÂðÜ|nš!¼ò£]¿}ôwÓJõõfùçw÷Ç×Kޙ՟͵~Æ(j&|%Qt¨¤Úæº#\ô•d:ÂTPMŽk#¬²¡&¿ìø¶¯ç·Özíý—Ñ×Á[£<­Ï»ÝCðzÕ»Ìo‰Îôå^I«˜Í4±­;F²ŸNLòà §U´fº:»I5n óë÷¬M§ù¾/=Kvõ^s ø=øô…G7ü)æ¶næo>ÞÙöþB¾Mì»gK¨RûÛ¨3,&ʈ“>BЉ÷Þ¡¶62Ç ~¨)õ¢~ˆéÀìâýˆªa"õ±´£j=TPÔöã´+í½m¹ Os}C„ü³•ÿúÏ„S×>ß̰ û¼œÁ³Îev­Œ9b-q׿à׸y*¸ƒüP}Øm«+SJPW¢p ë8…Z¨¨< ôˆé6 Œ)™0:zj¥ókÏm] m[ìêØåÜø6yØ]$^©ø>‘ ŸÎвØSñýiþ–L|Ýè?ñ÷{+˜¦~s>2}“ ©õ¬ø© tuZ~»í“οÿŸ½aýç™ ûã×§§¸føGÙ¶P–y¢“ˆw4Ahß—ÈæZÃýÕT"ŠˆÈÔ‘xëÒ6Œg‰½Q׸#µ°0‘Åž¢¿¦cu¯°dKOWžU.*{ê,,k2“b.!Ä]xýM[sß|p õï^ˆaGîu’_ý ÈÝ7.m©Î‘@“@ŽÐÚ#á?5GÚJ*ÿn§þ õIþ„ùÄðXì ¸~ /É©á«é6¿¯sl×Î(PI@M±O †!+Ã@@#ˆÔTÎÍÿ*ý0%I–I¡‰ fRA3 ˆ’FE!‘†I†ˆ“M‘‰„)„“a¢0‘ÚR0‚šFP‘L$¨bŠ) 1©&ËÁ$%IM!› @D’`(†”¤Â0Ä€¦HÍ£‰4¤ˆ ±AY @ È 0Æ)I”Âȉ…)&2IMщ% )Ê"šÂI#)@B1$!¨#¡’¡šJYƒa¡¥)±€LÄ!²c`Ɖ4HÄl˜ŒH’E1#% Rl2bˆRi¡ÂÐÓiŒ2ˆLd ((èJ1¥™,!”ÂII4Í0fÏé5·sdÌÆˆ’A’A a…“$™€b˜ˆŒ€Â)˜Â˜Á¢b0щ‘’e’Y$ Xi– $ŒY¡ÆL&2f(P¢ DÄ8?«=–-[íåI«³ñ™+G`,ZÁ´‚ÉD_ÆiG7_øã³Çðô[Cëâ{ÙÝï °ªÙÕ«Ä+Nå]rw Á޵ݞû=àç&g±Çr•Œ½þ>-G™Htì|í× ‡uBA” A*J›£Víq9¹ ¥ÆîáÛ·;iÛšæä‰Lº\Ò;®Ê溛©r’çH®sœÑs’’,¦w;nŒÀvv[  !¦ÆHš)a (LÌdJe£bÄ•….ÛuÜ»·Ućn¹Ívêî.â¹”Üê"L(ˆH¨£$ ’—7dÑ)‚f—m.»uØD™]»G7Nrç ¤¤ »pÄݸ»]n¦GdN®¢Â¦„Âwr#šéÄ&ÊHhŒ )0ÐÄË.®í]Ü’E;»0JG]Nåu‘É+¦äšPÉ6;·d„qÛ¬pìØH„Šn®­Û a-…€2R#ªæ¥ÄAÎí]Ã! î¸î» ¦Lº»ƒ¶ÖœK—:tstL‚—.¤nšìiMÕwiÛh»¡vî»UÚêKvÎ×bruÌÉ‘€Qcáb®“#2†]Ý2J3 ™RDÂ)š‰” ’U;˜àÑ£?çã‡Ìö]Öàûzß—ØÝvå”ä,àÁéé‹yÞÙf?ø¾Ï¦^òdPF DIE„Ei±ŸáÀT9N¯oÌâ·7¹-7OÿË×}óÞåiËʇj§xiBQªÕtø ›ÿ­®àü«µ¦xDZÝ%DÙÚž—޵Á&Ô }måÝD÷°-âèMÆJ!¬Ê*Úî„Èÿ'ð¯½ø¥É{zqI! ’s\]ãÎôDÁû ‡°ÙË8Ýú¯nÚÔê eËú’F6T¯ëÑÓ0Z»Í¨³ˆãAøê]—ãTEU¿²Poòw¦üß§Q”á¸ïKØj>ù-2º~‰žãFÙvá~Æ8ù7߬;ùéÀÏ€¥¢ˆ‰þ^kÓžàí"*‡u—÷³ËòžX7kGúè.˜ÝEòµÙ—7:±ÉÖXKæÛ¼dI‘ÄUBŽ0*,ˆš=]sžë¯ýŸëÚîÛËÝ{ªÔ\ûÚ¿¾X¿Ms6Ò«*9£íà Ûo•ßO×µøp;õv±äiˆå,£QVÖvŽÐb.Ù!†ÒøY?¯?”î&¾'CúŽPì› ÓÛ3/׿[šáäà9Žcª~9y¢ñ ì ƒrÍ„ùGZ00¾.äUþöéW†ÚÍû:þ¹|NZçÛíÛ4LÀƒTP®–ö£ÂÌǤN€‚IvóËÅaÆ^¹†ïê9Ê<,OÑCiByØcŽn{ØRÝEYÜ—+õ\°÷O§Áy^O ³-ä ÀcÕ ü mbË+ðBA(ˆHA°­´†¿+¼uµ×ŒƒåÁ!^sÉíœ<_‘˜Š)Qê6‚AüEÍY2@gÂÎûÖ½£þyãÙcmî& ¤Ö‘ AU–TÐ/ªOãî=î^±lÈ/%Ú†#öò†‹ê]ÓWªß{ïs”Ã~Y‰µR.—鬃ß{TqÖËï¨Òë{Ÿ#¶î²_f‚£êOû¹)ô§ w(½húwÔà ïý{Fazû|¿V’¾.Eì5›U¡µý9TñÞ¿ç™þ¤E¼ŸOm·ð¤úœg£üM‘À‘G(!uÃXF‹­ƒ•±½³öóvÞ÷›¹õ<ܾŠ:>áöw=ðE3õ‹@"PÞIV¬†Õ+q\÷—龟+þq|]ön¿ ÒwøNOgòQŽ’¡ŒØ»EèUtÜWK±î¿.¾ƒ×Ù>ªGmÓiÙ>ˆÊmö ÇYâ¯ü0š’šñu‰Ž#“õžg­·[—Ë¿AÔtz¬ÔéscÕëêDöá°ÚûCF?ˆÀ½y÷0X'¡µúYÿíܺftS5A* ïü¾àÔÜxº·h ×{Ý©ßx=ÛXÞ ÑOžßMʆÃ% nÄiiõ}·k„ùÝp<̨ÄÙƒvd÷r¸zty —tÍ~xÈd!B’N/ĺn7}ßoh|Ë—ÿY4=Kÿš3èܼ­#êYùôœÃ!ÍÁÌZ{=¯èöVy©š™d•RM÷ 1¬Ïù»s9Þâìü/£s¿þ¹x¯«;uÏÙáAß{Ád=þ*RÑ>dV y ¦A’@$¤¨4hØ6+à·4m’´[ø¶åª6ƒoÈ9²Q÷}ÆÑFÉIª-÷«mËdÚ4—äVå¢ÑcQ¶Æˆ-Ç­¹„ }ÂÚåûNíAXÕî]±¡5£_³*åQQZ4Z5ƒZHÚÆ(±¶ÆÔm¢ ¶5X F6°h´•¬EE¢#I‹E¨ÅDTE©6ÁE¤Ñb&PFŠ´j1«ûíhƨ«&Å¢Ö,ck_Ï­¹±¨µÑdcBd؈µï»QXÔZ1Ôo²¹¢¢ÁµFÑ¿îmø¯å{j¾·Óíµ¾ ±dªLllTmhÕ+c[llmQ»Îµ¼X¶%[}³]±ÿäiEæ¾ שÛ¦Àdá?ì j±–ßçVøîï â94ïÀ&ÑÌGQœÝ»Þ›¼ŽÆVàù^F[JÚ2¨"í D¦w3€ex]×äÞ8ŒnV圜‰òç´á¨l˜è.MÓ‡÷mëñ¶ˆ ?Ú¬Næ3±Æ–bŸ; Æ Gtm[Ïï€ùø¿ÛÛ”í·Ë—gÛ“–-P›#SdY¥%”Êbš@$QšM2‰D R¡)‹4`´€2@BRŠb4Õš Yµ™†çzßW”d%ú¯èç­ã—[Ft, ¦ë†¼3UkÔÿæý¿ŸgÎh¾—¤J%€ÃA)y>^y¶¯oñtY_J87N‰G“x_©dÏôTV,±®R-8N䨔ÍEùCÄ2ëÎlìv‰zÇÿÍàÙEGýÍ©H°þò~¾¸±b*Wšô–*‹ˆBßha¡“ÏôªÉ*ßÒÒ Ë#Û?pvÈÂÜnEQã „ë Þ-Œ/‡wÝÚÓÔrJšYS¾"#,©JÒ½ ›™ …Èö88{+ƒÐ FÞØ­F€¤û*›¹míåâˆÿ”%¤!á”wç#zQ§}lHíX8­ @qŒîùŒÞ8€îEB»ŒfáŠ%ÆÉ ÿмñýªÉŠ:â†SÚô.}Ê8ž—=úí¹aKÿÜ©(ñ FRR¨œè×È‘¶Ìû¯°µý[\vÈÚrcÆf+òpsf±üôM‡g}²í2…$“0©Aê*¼xæ/Ô~וPm×(싯žôýÏâ͟𷻣 ø3°ÇdÿŠ>¯ ?KÚ£Œæó­ù»ÌEŒQõÕI'3¤êû;gm2.2âG¥…Owq\4(#tæ±Ýc¸ÜRi“˜ï盘£ç3Ccè*­<¦„1¤œVüL|~þº~…?aÕÿ“†ÂaV àWêÞ~ë&Ý@ã×û `§ÄJ'Ó˜£:úCÌô´|iy‰+*,ª‰¬–"¸ŸÏsCäé)ÙÅ|T?Æäÿ&H?Iú”[…Û©KÑžø_¯t‹µôo:ZÉÞy›¶4±¨ñÞ D R•U@”‹ùnÔþrdÃ&˜î¯²Bæ>¾øÚõO\òyO+ª`ßòLd’|¥Ô™än|[âÜ€{„ |¸äê³¾G¼à–dD|7*  CNJä·é“Á·¥ ƪ(±!âœYÊ©RcÇÝþVußô„”0~Ýï9µ¤ö¿1½¿K¤™·»_¨ðù>ëãö_.1RëkG´·r‚š¿'ÂòݳßúÊonûVÕxMÎñøó(l°Ë$„í\ozAû^—y}veózãñ¢þ'üÜLS@-vé€@žN¿…öáwÂ)”ºÄè}£ s8¼§y­ù8[¿oØk5[mÓwXgÍž/lYŠ. ¸+ØòöÞ?ÄÏÚnœ÷¨‡×È»|‚¦@&}bÏãx¾/sÃj¼}·ïÉoXîW ôâÃ0’d6Ïúð¥½ÑÛ¯ûÛ{’?³Ú»ª4Û/]OÖÎ_òý&]¹N{“D$­õ¶õÊ™ ½‹¢ê½ƒ—à‡QÁ<98Q ÌÂŒºŒ‚e,÷_Ãöl^¶¢­ÿþ°U9]©sSÂé$rUn »-_aœ÷¬¿šîWiÔhüHý¿n³­9;É㢓¨Ž´Ý¸e¡Â¬5ˆP­nCƒ³Óí¤Vÿ‰É@`´C‰:¸ù)1Î&è¼Þÿ¦}¾ÞU©Ål?L½Û‡å–D‚€Ø{Ì©³¢Ûb/{ßçÀwYÖ³à×U|S¢K§Nä’¨R0¡ºvÌnl¨{C÷r[Lãõv€m|—¹¬• |ÞŠrÀ;„3Œñá¼ 0r2…±mNn³úé¢YË­¹,¨Ùè4Bo¹çßÏxúµä_óñÁ[Þ_™€‹“æ5ÔC¹ÏR4ÈËðÀÐ9£Ú`Á$’I’-Ãn =_A¼Iæý­_WÐû>¬p¤¼¸ÿz社.Ü}SDð*ǘjß· ¹­ûÇT¡N›»þ~Gpø™8E2ŠÍ–A¦öÉ{ðZò™M#/]¤½Ê@@—郗“‡Ä+SÙCL†H2á’/+Òñæ\ï¿«õ­Ù=àŠ”ÒTL`l†ƒ¨Ïƒ h<ÔhNÁ(éØ`'¥I$‚ˆ‹# ×E’ˆQD[àzGÀÝqþú~›ðèóرQvw1Ú~0 ‚ȪBÉRWVÔ[`“¶*A 2bÕœÃG ÛßõnäÓL=­¼ê¿ÿ1AY&SY€Mñ&ÝÿÿÿÿïÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþwþßßÿÿÞÿÿà¿^öcÀ\ÍA§ 5Ž Ó¹’IÛztOÀë4{µïu½åìñÚî€èA Bhb›F@44SO)èÑOÈž§©µ¯t›Ó#KXˆC‹‘«* Ï³ Z儸HÒ¨Ò#*F#ÚÅ„EFù‚-% 4Y Yi°HÒª¢Šåˆ²ÌDWøH¶IDc(ÓóJ¶>\TZRÒ¤’îBÌU&"ÖrR(ÕÐ_ËÓN•(”£y")…’×akV.À1n9;³)¸1Ó^-r¥Õ®ì\-?/ìGTÀª5á²—! Œ‡´N²oTîv W4Š-Þêÿ³€Ž9~ª˜£#ƒJþ°ˆL•ZÀÛW Â-Šd·Ô÷ðH $ÊJ(ˆ€‚ € Ò-#B”*´Ð"´ ¢Ò Ð"*ª(ffFa@ˆ¿œ‰8²1RÉŒžC¿ïŽîl¡à&ñ>âX…¨ä}e‘‡ðÿ¹G.›P@fåì·ŒÊlri¬1ïëTþøiÛ^mÇF~nŸ×ý ´ã¥ªÜ'ñëÞ$|< ¬× 7q4'ÄDZõd¬Ÿe:v‚œ zÃS8x™Åa7ø¥£®|ª§»º9ã—CÖ=[áóçê:zS¦”&d´u·%]i£ ›fXËLßÕоº2qˈ¢NC¥Ö«F Ùí¹ûË7êQT4j¶hÅ Œb]@èë–‘×”ÊnëÞØ»“á š)½Òk^Ò¦‘Cܘ·­§'S¤äî:[#L‘íò‰šmæz…f’ßlrëí ÅÚÔ‹Õi4>·©¡¹æ€"*õTòVÛUíUcgw£Z·OìMcÝ6ŠÍEFõë—ÍPý•KD6*xh‚©5‰¶4Æ'­Ã¢gêu «gL{}Ñ÷WdÜÔÊZá:؉Ö\>•ŠÛ×U~ôÍ% ŸóPËä)d;G,u¢@®ÙK‰_ctë·ìr¬ê?ìåŒ) »ÎÛËѬÇt€ã•‡(K Þ`°vBèIB‚‹q-FåÕŦãnW$)§P•t^FAžÒ$Øû“Gi²Ýº LlÈa£§*M翈bX&#nàt<^ ï*ÒýéÑ03(Äj3ìv ' ªGlÁ:¤¤ZgLKÏûÔÖŒ`0„=šoîűjReCCÊ„‘á6‚/k:Å~r5["Kš"çÌD«Èv5YÐs:n"NêÞ÷w¹î @?©~9oåÏÑÆ“•¶v—™"A‚ &è’§9» I£û2õ"3Z1'H„AÚ‚" `xVIš0c;‡Ü[ܸÚq¤…Šáü™W£êj·»oEc|Â¥ºÒ1'z­Cåè‡2Q¨'vzÓ}úüîðlÇLÁ™”ï%‡Z‘â}Y .í¿ˆáÆK†,eAŒ–ªcà(ÿ¤ zÖ½õ€e㨠?0½ú7 ”¹ËW;d:1÷7”3î}ŽÝ{_ùh(Póuæá´ñÁ™ógçÓ•w‡OÄþs|ß=Q=YÕJ¡Ëü€¦ØfOÁ¥ô¢M5›)«ëÙ…Èn|xhF7Æ`õ²è dÎ)ý×6bãÓ§É7«õñ:‹õe?åd$áÛ]op¿ßõ»¥ãyoá=Mtwç1L6òÐé$Pdötu!KHý-¹ZJU“Öâú F¿.g»ÜÜr÷fégÄ»¡Óɳ¹4p•CÝÖ|±ìýþ¥ºBÀKÅÖÎ<6 ‹Þrƒ‡æDaG/ÖÖ{«Rõð÷ ]< vA¤4g>Ú’R‡]þu»†Äp×ô1Âl§ÍÐ3ô‘Å1ƒ³å ·ÓB¼ÑT p“ ÅÓ"÷FBNn44kÔ8â¼âP—OÇ0Í+¤ØZ¨ ½õ•” ¼ ŒzD «‚à ¬9ÌMŒŒ!`FÐá·ÐÁ{oN'' ­ 44q6‘ÞÖ¹Bi¡Í ʸºFlêâ9Ú,²¡Ѱz½’ާ/ÏC}¨1äæB‚®$ÐÀ>@4oòü#š2Uºq#ªkÙ¥/oO‰1xæ²ÐO;P÷‹nÏ”h(]Js}”3˜”“{ÇKYÆÐk#2×Ì’”!U¯`°?÷úXH@½†P”‚…Y(ÒWˆ¥‰™‡(ér(¼þøq±K˜ÛÆÓ \1KjÀË@¦µð-¦ÝÄnšW1&˜Áƒo–¿%Á³Ü!!ãCSÓZüè1ƒѡόRæá¶ FynYZÚ¾öGŠÔWî*‡†iL­– $ÝÖî 'Bóã0zÂÌæyEHCÃ0†s¿Då* €ªÍ°g-¨²žÛT? &&E¦e 4ÄH±€Â(¢y£Ry‰Ò¡²Uφéo­ª ¶Ës6ƒM—ßš”8M#.:¤Øó[„¦kVn!–A''Œ³™æú5ݸ46 Z`DÀ±›Ã@3"ª JTÁŽg7]š¥#¶Ëù_‡ˆ…ø Ú{ú¬¶„qè1("Y|knW€Î”ÁnäÑ» Y]Š,+d‹ž§sÎE%Ÿw[1[þ(ø^0à±$`AùHAÍ4¦…©YÓê>n*(ŒeøäÑêÐØ·ÌlQZ2IX!°Zk™7¾Ù–ªI Hž*©O jÔm´0³4š_*$$ó«¡ l½]` H´óý¤âO‡¾0Ž’ 3#¶écÞ’i@[®ÉVh(6 ·Í«Ýݳ)[²¼x_fœ‰6g¯!¤AÆff dr(CË–òb Ãx0BëÌf'ì%N·õÁnš†,‘RŒqy²F& ÕfîÞ¯q“ ¤”t‚C Ùe\ÏeØ{Fž¡Š‡#§@Á`·1JôJžÊ`±9F54Úh3U˜ŠÅƒD½âÿ££†¸)cHµC+I&Á ï Îz¼Ñº®ÃJ´c…2ÅŸ÷H(ÓÃm‰›Íðs)¼‡Zã`ÄÝ-J‰hé+·ªðqu‹ÉÇÑP Èj‘{\l%܄욗$†KL¬oÆ2˜ 8ìžs/öÃzAË« ëbJ†à†rSƒØ+À¸³3i椕æÛ-ÆÀb^­gLD;é"þbjðbWYY+š„B5BØB"Ù"%¡ª7£Wš]íÝq4/‡¹‡³p÷ô¥¹7$‹XÐÙ›-mIda±)ÚÄR}¼/˜ybc€4TVT#vÖiœÑ“ìKH3 GI¸ÆÕbz¬B Íg¥'r‚UP)%QÃñ²VIXÒMŠk×mfQ_TZÒ¡4”¤1ÀÈV76¥$.1 &iwÝPzU¯#mLÛóXH1¼$ÃÆ… I_¾YÑIÙÐC°  38EüžŒ½d¹d¢ªx I«Éåg üe,¡¡&Ým•ŠDD¤ÂÆÄæ9±¦ØÑaä"'Be’QJDì"S€±XÓp30å5C`Úd×q¹}>¨³L$yõÙ‹Ï„®Œ)|8 sœY #ßwCÒµçëÇ- tIliñ± }lÐÓ`âÍî¢Ô69Ó$€]““¿™V „Ÿ¤4¯ÀÄèÜ÷¯ YŒ‡.¨C xB”ÏÅQì™TC„ÎFrã2àMÙpˆrÐ(( ŒRÚä™)'tïYtKÀí" a·Ü¯µ½@¥µ!‹„2 Š#X³§¦Ù ÏÁxŠw\¯iÍô^šŽ¢Ê¿®D§A_X+(ÆB@Ð ó ÈÕ¸Eduñ¢Ö… ºl<˜* ·+-T¾/]ô;,8n Àæ1“[½KµèyºÕ«FšiØ £eJ%Îtœ ç+È÷ˆÎpRmT£pNòqD±—.ónÞ€ò¢Ð­˜–9æQTa^UTžÔÉ ªN¡©ÀÚ-’Zù•’˜ËBÔš`³gu %ƒV D,¤à’›!G‡'³3…mù(16!é½}ùS%" "¥›w»':´ßjW "ÈñfÃ"÷E¦²íFö÷Ç›2ÆEÔ ¨T,P‚I]‘AcpßÕ7qLSlÍJÄDŒ…@Ž}U_ªÐmêB3ÈË,ˆ¦K9ë†öÒÐíy%4%b„P:”!<÷ `„ö€VŽ1ÕÚ¡¥” ò'Ùæ_—])©¨ºojßB ÓtUð'€år6é¼#Ôè1:ËÕYQl Bv å„ p#sHÞS#´©¾4:øŽ=¡Z…Z®j󽫱§®Ad¤$s`±4ˆÚVHDÁ¡S4æd`*#“ëof_Rà4µÄ[ÒùÛØæÓ¨¹ÃHY…Âç{¨b8i’˜’‰)ƒ@ˆ^¡lÃ`À°¹ž†Qt b0Èl@1àÖ页=c9v´±vo°É<×§s¸•Uä휢2¯E¦â;È3ò¨w:ñ¾Îáf‘ÃH߬õá¬ú ä˜ØÐmÙ”ϯÐâKµx¡±¡Ú š-‰Æ'“p£¦¶¡˜ˆ¸›Ë;ˆM6& ƒ±RÅWÓÖ ÀIi’etÙ0óµ»üu‘X_ÂLò'¾¥SC“~"1_,fƒg¬Í[¨Û¡Àú.lˆƒ7±Ó "™: c¨lS[ÚÏ%b ÔQ’,'W€¤M°™‹|\¶‹Í+7šÁî4[ï„®ùª˜qGRy$íÎD JùÖ1;{}…Š'!ÑsL² ÔQH#*‰{ãa1»ž/ûÅi{ǵùdÌw{}Xc­¨ÿ+`8!!µ ) >š  ´”’PšH€FåˆJM{Bs±zô{0”’]WƒÉH<°ýŠ …PLN*-i—ëI#5ýý¸Ýêûí€Uóq1 òj¹Y*]Q¶¥¢EÍÓ7:‘ÌBÃ.sS zü*æ„CÌÆ =y鵎FƂӆ.O˜q»Xq£°ð&™@#ºn̲ÓN³c5kÙ3P¥wvd¤!⹂åÆî«`‰‹à#‚,͈PU$ÂÚ•{NêîÎøò«(A$‰Òº†«xâwò‰$†6™/h³lÒš+ªN’CA•zÌ®P’ F”#4S”¢R(‚"PÝWÕU·1·Üúð`†÷a-âs$DÈØõ‚ ‘QZª+‰Ó0ÆB̲»›–Ó"ë&›θAZ[M|º£hsALõjm!ò5*íPW0&T¬(f™0Í(€`Á€å–˜FKAqŒ(L3 0Ž[™)Tà‘C©Nj*d&jP Þ*"k”œ+ƒžˆÆ°ärp{æ¸]ÂøÕg€‹ÆQSLRe¬*ÜÖš"ª#È+n"›¢ Ëð éh±ð ô.H‚´ÐT›}*ë‘É–›˜D.—¸YF–•òÂ’(Ø´ ¦•ÑJ(3}-ª†bºx …>0'eâ"B¶KûåjU&ÁýR‡XæUŽ~Pn¯Ã<Õm¡éž(—›5¤Ð,´èLƒçù#/Û¬È" kT0M;qذY¥c*ò¸èR¢J ƒ! ÉD¥1¥"F+àÍ®ä½-¶EÅ»®{2æqH>2 ­®‘‚ª ¡ 2"þS¬w&n¬ù0‹¬÷Ã/пe#F®IÙ´4ý;¬+«ìy­Øã>¡ã©}}²Q‡•´RAÈi—uõÿp BמL¸Ö•æÃµ¬vɲÉ®äíW¤…6z*KO;ËHÜK·Ü€tWI»ü:äiˆŠW+‘ç§}éïjQ¹¦–Á±ð‚ˆdym÷ÄD@bz2-1.0.0.1/test/data/sample2.ref0000644000000000000000000063656407346545000014512 0ustar0000000000000000÷ƒ’À;è TeX output 1995.10.19:1430‹ÿÿÿÿ •ºâ ý? £ þŸŒ÷‘dßdóÂÖN ff cmbx12¼Strictness–ffAnalysis‘I™‘ø4a“Grande“Vitesse:ޤ‘¼¦Rewriting–ffthe“rules“of“the“Ev‘ÿ™aluation“T‘þ¦fransformers“gameŽ¡‘5†ÈóX«Q ff cmr12»Second–³/draft:›D>OctobdCer“19,“1995.˜Commenš›¼ts“are“w˜elcomed.ŸúÆ=ó !",š cmsy10¸ŽŽŽŸy”’È@ó(Kñ`y ó3 cmr10ÓJulian‘¦fSew²!ardŽŽ¤ ™™‘5)JDepartmenš²!t–¦fof“Computer“Science,“Univ˜ersit˜y“of“Manc˜hester,“M13“9PL,“UKŽŽ¡’°>?ó7ßê]“and“[Sew93Ž‘/]),‘гand“put“m•¾9uc“h–¿Še ort“in¾9to“devisingŽ¡’õºâpšAÇolymorphic–¢analysis“metho˜ds“[Bar91Ž‘ U].‘5Y‘ÿ:«et“the“feared“co˜deŽ¡’õºâexplosion,–Ò›it›Áíseems,“simply˜do•AÇes˜not˜happ“en.‘£Measuremen¾9tsŽ¡’õºâbš¾9y–›“Int“->“Intº,˜comparisons‘{ÇëM(<)º,˜ëM(<=)º,Ž¡‘íºâëM(==)º,–n¾ëM(/=)º,“ëM(>)–Eºand“ëM(>=)º,›n¾of“t¾9ypAÇe“ëMInt–¹–->“Int“->“Boolº,˜andŽ¡‘íºâcon•¾9v“ersion–=ífunctions“ëMchr“ºand“ëMord“ºof“t¾9ypAÇe“ëMInt–¹–->“Char‘=íºandŽ¡‘íºâëMChar–¹–->“Int–¦ÍºrespAÇectivš¾9ely‘ÿ:«.‘ÐÚA‘¦§v‘ÿ|ralid“program“m˜ust“supply“aŽ¡‘íºâbinding–»for“ëMmainº,‘Íbut“unlikš¾9e“a“Hask˜ell“program,‘Íthis“ma˜y“bAÇeŽ¡‘íºâof–Tanš¾9y“t˜ypAÇe.ަ‘íºâDespite–iÉthis“meagre“collection“of“primitivš¾9es,‘¾æAnna“kno˜wsŽ¡‘íºâabAÇout–fmost“of“the“built-in“Haskš¾9ell“t˜ypšAÇes,‘‰including“b˜o˜oleans,Ž¡‘íºâc¾9haracters,–T„strings,“lists–Gáand“tuples.‘´Although“some“impAÇor-ŽŽŽ ý€’õºâtanš¾9t–Ü»features“of“Hask˜ell“are“missing,‘è the“subset“allo˜ws“Annaޤ ’õºâto–:CbAÇe“fed“real-wš¾9orld“programs“of“considerable“complexit˜y‘ÿ:«,Ž¡’õºâalbAÇeit–Tafter“some“considerable“massaging.Ž© ’õºâProbably–g)the“bAÇest“w•¾9a“y–g)to“think“of“Anna“is“as“a“framew¾9orkŽ¡’õºâfor–¡Itrying“out“new“analysis“tec¾9hniques.‘ÀNHence,‘ÄFthe“systemŽ¡’õºâlogically–%Ýconsists“of“t•¾9w“o–%Ýparts:‘=‚the“analysis“propAÇer,‘)ÿand“theŽ¡’õºâsuppAÇorting–uÏframewš¾9ork.‘=àThe“in˜terface“bAÇet˜w˜een“the“t˜w˜o“isŽ¡’õºâreasonably–ÃVclean,‘Ó¼so“c¾9hanging“the“nature“of“the“analysis“canŽ¡’õºâbAÇe–Íudone“without“m•¾9uc“h›Íuuphea“v‘ÿ|ral.‘DÓThis˜section˜foAÇcusses˜onŽ¡’õºâthe–TsuppAÇorting“framew¾9ork.ަ’õºâBecause–×'wš¾9e“w˜an˜t“to“exercise“the“analyses“on“functional“pro-Ž¡’õºâgrams–T'of“realistic“size,‘zÊthe“suppAÇorting“framew¾9ork“is“necessar-Ž¡’õºâily–¼Ûlarge“and“complex.‘þòIndeed,‘Îthe“analysis“part“is“curren¾9tlyŽ¡’õºâthe–è¶smaller“of“the“t•¾9w“o.‘–•The›è¶framew“ork˜con“tains˜a˜go•AÇo“dlyŽ¡’õºâpart–Áof“what“one“migh¾9t“expAÇect“to“ nd“in“a“full-scale“com-Ž¡’õºâpiler–Tfor“the“same“language:ŽŸÐO’äóP©±Ê cmsy9ëPŽŽŽ’ :âºF‘ÿ:«ollo¾9wing–= the“parsing“stage,‘†÷desugaring“and“patternŽ¡’ :âmatc¾9hing–0ãtransformations“are“carried“out.‘oThese“pro-Ž¡’ :âduce–ÝyëNCoreº,‘O‚a“minimal“functional“language“used“asŽ¡’ :âan– -inš¾9termediate“form“in“the“Glasgo˜w“Hask˜ell“com-Ž¡’ :âpiler–îž[PHHP93Ž‘#µø],‘ö\and“tš¾9ypical“of“the“in˜termediate“formsŽ¡’ :âof–|Ïv‘ÿ|rarious“other“compilers,‘–®for“example“the“ChalmersŽ¡’ :âHask¾9ell-B‘¶}Compiler–¶§[Aug87Ž‘ó'].‘hAll“further“transforma-Ž¡’ :âtions–òprior“to“strictness“analysis“propAÇer“are“Core-to-Ž¡’ :âCore‘Ttransformations.Ž©34’äëPŽŽŽ’ :âºA‘MÌdepAÇendancy–Nanalysis“phase“splits“the“program“upŽ¡’ :âinš¾9to–µyminimal“m˜utually“recursiv˜e“groups,‘and“marksŽ¡’ :ânon-recursivš¾9e–M>bindings“as“suc˜h.‘Ä.All“subsequen˜t“trans-Ž¡’ :âformations–Bare“required“to“main¾9tain“depAÇendancy“order.ަ’äëPŽŽŽ’ :âºA‘Ízcrude–ÍŒbut“e ectivš¾9e“Core“simpli cation“pass“remo˜v˜esŽ¡’ :âunš¾9used– ºbindings,‘ Øand“substitutes“in“constan˜t“bindingsŽ¡’ :âonly–:used“once.‘ÆThis“helps“to“clean“up“the“rather“messyŽ¡’ :âoutput–`-of“the“desugarer.‘üûThe“former“feature“is“usefulŽ¡’ :âfor–;ždebugging“the“analyser.‘ÓÞBecause“a“binding“for“ëMmainŽ¡’ :âºmš¾9ust–“ìbAÇe“supplied,‘­Îthe“simpli er“will“ev˜en˜tually“remo˜v˜eŽ¡’ :âall–´bindings“not“reac¾9hable“from“ëMmainº.‘êIf“the“analyser“isŽ¡’ :âseen–‘¹to“malfunction,‘¬ arbitrary“subsections“of“the“inputŽ¡’ :âprogram–can“bAÇe“discarded“simply“bš¾9y“c˜hanging“the“b•AÇo“dyŽ¡’ :âof–¥ëMmainº,‘Éunš¾9til“what“remains“is“small“enough“to“mak˜eŽ¡’ :âdebugging‘Tviable.ަ’äëPŽŽŽ’ :âºRemoš¾9ving–.“nested“en˜vironmen˜ts“mak˜es“subsequen˜tŽ¡’ :âtransformations–i®and“analyses“simpler.‘ã9T‘ÿ:«o“this“end,‘ŒtheŽ¡’ :âprogram–Vis“ attened“out“bš¾9y“a“moAÇdi ed“Johnsson-st˜yleŽ¡’ :âlam•¾9bAÇda-lifter›‰[Joh85Ž‘Ä9],‘¥!follo“w“ed˜b“y˜another˜depAÇendancyŽ¡’ :âanalysis‘Tpass.ަ’äëPŽŽŽ’ :âºThe– Ûprogram“is“noš¾9w“t˜ypAÇec˜hec˜k˜ed,‘¼using“a“standardŽ¡’ :âMilner-Hindley–ƒinferencer“deriv¾9ed“from“Chapter“9“ofŽ¡’ :âPš¾9eyton–…uJones'“b•AÇo“ok–…u[P˜ey87Ž‘Hª].‘lÒEv˜ery“noAÇde“in“the“CoreŽ¡’ :âtree–;has“a“tš¾9ypAÇe“expression“attac˜hed.‘hAlthough“a“com-Ž¡’ :âplete–mannotation“is“rather“expAÇensivš¾9e,‘ ³it“is“essen˜tial“forŽ¡’ :âsubsequen¾9t‘Tpasses.ަ’äëPŽŽŽ’ :âºThe–þNsingle“most“complicated“transformation,‘8Œhigher-Ž¡’ :âorder–ôfunction“remoš¾9v‘ÿ|ral“(also“kno˜wn“as“spAÇecialisationŽ¡’ :âor–z rsti cation)“noš¾9w“follo˜ws.‘(âThe“presen˜t“naiv˜e“im-Ž¡’ :âplemen¾9tation,›|xdescribAÇed–g×in“Section“5,˜is“slo¾9w“but“cor-Ž¡’ :ârect.‘™cMost–é¥if“not“all“of“the“higher-orderness“of“t¾9ypi-Ž¡’ :âcal–Q™programs“can“bAÇe“remo•¾9v“ed.‘Ñ>This–Q™transformation“isŽ¡’ :âcomplicated–¹ybš¾9y“the“need“to“main˜tain“t˜ypAÇe“annotationsŽ¡’ :âcorrectly‘ÿ:«.ŽŽŽŽŽŸ’çjã2ŽŽŒ‹ •ºâ ý? £ ý€‘ûäëPŽŽŽ‘:âºFinally‘ÿ:«,‘ŸSthe–ƒºprogram“is“monomorphised.‘g¡This“pass“isޤ ‘:âquicš¾9k–Ÿand“relativ˜ely“painless,‘\ev˜en“though“a“third“tripŽ¡‘:âthrough–Ó•the“depAÇendancy“analyser“is“subsequen¾9tly“re-Ž¡‘:âquired.Ž©Ù‘íºâMost–†£compilers“wš¾9ould“w˜an˜t“to“mangle“the“output“of“theŽ¡‘íºâdesugarer–5rin“quite“di erenš¾9t“w˜a˜ys“to“generate“go•AÇo“d‘5rco“de.‘ÑÏF‘ÿ:«or-Ž¡‘íºâtunately‘ÿ:«,‘Ñ it–«is“easy“to“see“ho¾9w“the“output“of“the“strictnessŽ¡‘íºâanalyser–ççpropšAÇer“p˜ertains“to“the“desugared“program.‘”)OnlyŽ¡‘íºât•¾9w“o–Ttransformations“givš¾9e“m˜uc˜h“trouble:ŽŸØ‘ûäëPŽŽŽ‘:âºLamš¾9bAÇda-lifting–psimply“mo˜v˜es“bindings“from“inner“lev-Ž¡‘:âels–Véto“the“top“lev¾9el,‘|ÿand“adds“extra“parameters.‘Ü÷With“aŽ¡‘:âlittle›¢bb•AÇo“okk¾9eeping,‘¹_it˜is˜p“ossible˜to˜k•¾9eep˜trac“k˜of˜whereŽ¡‘:ânested–pŸbindings“ended“up,‘‡rso“that“strictness“informa-Ž¡‘:âtion–Tcan“bAÇe“related“bac¾9k“to“them.ŽŸ×x‘ûäëPŽŽŽ‘:âºHigher-order–1tfunction“remoš¾9v‘ÿ|ral“will“only“ev˜er“remo˜v˜eŽ¡‘:âhigher-order–NTfunctions“whicš¾9h“ha˜v˜e“bAÇecome“irrelev‘ÿ|ran˜tŽ¡‘:âbšAÇecause–Gˆof“sp˜ecialisation.‘³ All“ rst-order“functions“areŽ¡‘:âpreservš¾9ed.‘ gwW‘ÿ:«e–.Vare“really“only“in˜terested“in“deriv-Ž¡‘:âing–†Xev‘ÿ|raluation“transformers“for“the“ rst“order“func-Ž¡‘:âtions.‘$ëThis–m}is“bAÇecause“the“demand“propagated“acrossŽ¡‘:âa–ÿ/higher-order“function“largely“depAÇends“on“what“theŽ¡‘:âhigher-order–@Eparameter“is.‘ÕkSo“exploiting“demand“prop-Ž¡‘:âagation–Xacross“higher-order“functions“means“run¾9timeŽ¡‘:âmanipulation–×of“ev‘ÿ|raluation“transformers,‘‡|a“seriousŽ¡‘:âcomplication–Tfor“parallel“graph“reduction“systems.ަ‘íºâBuilding–¿Áand“mainš¾9taining“the“framew˜ork“is“a“tiresome,‘ÐÞtimeŽ¡‘íºâconsuming–z°task.‘èäOne“could“also“argue“all“that“e ort“w¾9as“un-Ž¡‘íºânecessarily‘ÿ:«,‘%_bAÇecause–"*the“Glasgoš¾9w“Hask˜ell“team“ha˜v˜e“spAÇeci -Ž¡‘íºâcally–þdesigned“their“compiler“as“a“basis“for“expAÇerimenš¾9ts“lik˜eŽ¡‘íºâthis,‘º5and–f v‘ÿ|ralianš¾9tly“suppAÇorted“those“bra˜v˜e“enough“to“tak˜eŽ¡‘íºâthem–¡´up“[PHHP93Ž‘#µø].‘ÁIn“retrospAÇect,‘ÄÌthere“are“three“reasonsŽ¡‘íºâwhš¾9y–TAnna“w˜as“not“built“in˜to“Glasgo˜w“Hask˜ell:ŽŸØ‘ø‰1.ŽŽŽ‘:âAš¾9t–Ïçthe“time“w˜ork“on“Anna“bAÇegun,‘þ‹in“the“summer“ofŽ¡‘:â1991,‘ÖGlasgoš¾9w's–¼compiler“(v˜ersion“0.02)“w˜as“in“still“inŽ¡‘:âthe–TproAÇcess“of“dev•¾9elopmen“t.Ž©×x‘ø‰2.ŽŽŽ‘:âUn•¾9til›gFrecen“tly‘ÿ:«,‘»Ãthe˜analyser˜w“as˜relativ“ely˜feeble,‘»ÃsoŽ¡‘:âthe–ú¹need“to“feed“it“realistic“Hask¾9ell“programs“has“onlyŽ¡‘:ârecen¾9tly‘Tarisen.ަ‘ø‰3.ŽŽŽ‘:âThe–…Ïmost“impAÇortan¾9t“reason,–¢ƒthough,“is–…Ïthis:‘Ô­Anna“hadŽ¡‘:âb•AÇeen›êdev¾9elop“ed˜using˜Mark˜Jones'˜marv•¾9ellous˜in“terac-Ž¡‘:âtiv•¾9e›¯?en“vironmen“t,‘êGofer.‘úiMerging˜Anna˜in“to˜the˜Glas-Ž¡‘:âgo•¾9w›À Hask“ell˜w“orld˜w“ould˜ha“v“e˜mean“t˜compiling˜withŽ¡‘:âa–yêHaskš¾9ell“compiler“and“this“w˜ould“easily“ha˜v˜e“put“anŽ¡‘:âorder–m£of“magnitude“on“the“edit-compile-run“cycle“time.ŽŸÙ‘íºâAs–Å€Anna“bšAÇecomes“more“and“more“p˜o•¾9w“erful,‘Õwthe›Å€incen“tiv“e˜toŽ¡‘íºâbuild–'it“inš¾9to“a“real“compiler“gro˜ws.‘êThis“is“de nitely“a“longŽ¡‘íºâterm‘Tob‘ƒŽjectiv¾9e.ŽŸ ‘íºâ¹2Ž‘ü”T‘ÿ,Ìechnical‘LÎp•¹™relimina“riesŽŸ†´‘íºâ2.1Ž‘G·Some‘LÎterminologyŽŸm‘íºâºThe–ÿanalyser's“fron¾9t“end“proAÇduces“a“ëNCore––Åsyn´Ctax“treeº,‘ *inŽ¡‘íºâwhic•¾9h›Rev“ery˜noAÇde˜is˜decorated˜with˜its˜t“ypAÇe.‘Ò¥This˜is˜fed˜toŽ¡‘íºâthe–oëNabstract‘¢bin´Cterpreter“ºpropAÇer,‘Bµwhic¾9h“translates“to“anŽ¡‘íºâabstract›9=form:‘dBëNrecursiv´Ce–Üádomain“equationsº.‘ˆ,The˜ëN x-Ž¡‘íºâpK¼oin´Cter–›€ºsolvš¾9es“these“equations“b˜y“iterating“to“their“greatestŽŽŽ ý€’õºâ xed–népAÇoinš¾9ts,‘…Ndetecting“equalit˜y“of“adjacen˜t“appro˜ximationsޤ ’õºâb¾9y–š³reducing“them“to“ëNnormal›ÿšform“ºusing“the“ëNterm˜rewrit-Ž¡’õºâing‘ŒÊsystemº,–Tand“comparing“those“normal“forms.ŽŸ ’õºâThere–Tare“t•¾9w“o–Tkinds“of“abstract“en•¾9tit“y‘ÿ:«.Ž©ÐO’äëPŽŽŽ’ :âëNCon´Ctexts–eºdenote“an“amoun¾9t“of“ev‘ÿ|raluation“that“shouldŽ¡’ :âbAÇe–àUapplied“to“a“data“structure“or“function.‘ }sTheseŽ¡’ :âare– Dsometimes“referred“to“as“ëNdemands“ºor“ëNbac•´Ckw“ardsŽ¡’ :âv‘ÿh‰aluesº,‘á¦but–…–wš¾9e“will“stic˜k“with“ëNcon´Ctext“ºwhere“pAÇos-Ž¡’ :âsible.‘ÑÊW‘ÿ:«e–ürlater“inš¾9troAÇduce“a“Hask˜ell“t˜ypAÇe“ëMContext“ºtoŽ¡’ :âmoAÇdel‘Tcon¾9texts.ŽŸ34’äëPŽŽŽ’ :âëNAbstract‘CFv‘ÿh‰alues–Õzºamounš¾9t“to“some“tric˜k˜ery“w˜e“will“in-Ž¡’ :âtroAÇduce–øÙto“deal“with“higher“order“functions.‘òAn“alter-Ž¡’ :ânativ•¾9e›ýname,‘['whic“h˜is˜again˜a“v“oided˜where˜pAÇossible,Ž¡’ :âis–"’ëNforw´Card‘œ v‘ÿh‰alueº.‘D*The“correspAÇonding“Haskš¾9ell“t˜ypAÇe“isŽ¡’ :âëMAbsValº.ަ’õºâThis–?¿papAÇer“is“primarily“concerned“with“disco•¾9v“ering‘?¿ho“wŽ¡’õºâsource–Ý(language“functions“bAÇeha•¾9v“e–Ý(viz-a-viz“con¾9texts.‘síNev-Ž¡’õºâertheless,‘ßgthe–¶ýoutput“of“the“abstract“in¾9terpreter“is“one“ab-Ž¡’õºâstract–EÙv›ÿ|ralue“pAÇer“Core“function.‘×GCon¾9texts“and“abstract“v˜aluesŽ¡’õºâin•¾9tert“wine,‘Öfso–¯Éthe“ëMContext“ºand“ëMAbsVal“ºtš¾9ypAÇes“are“m˜utuallyŽ¡’õºârecursivš¾9e.‘ÄThe–÷Üabstract“in˜terpreter“itself“is“de ned“as“theŽ¡’õºâfunction–TëMZ“ºin“section“3.6.1.Ž© ’õºâCon¾9texts–ˆand“abstract“v‘ÿ|ralues“are,›¤Zin“a“sense,˜strongly“t¾9ypAÇed.Ž¡’õºâEac•¾9h›£Bcon“text˜is˜a˜mem“bAÇer˜of˜a˜particular˜ëNcon´Ctext‘ udomainº,Ž¡’õºâand–nSmost“opAÇerations“on“con¾9texts“are“only“meaningful“if“theirŽ¡’õºâopAÇerands–ÿ8are“dra¾9wn“from“particular“domains.‘Abstract“v‘ÿ|ral-Ž¡’õºâues–zÌare“also“strongly“t¾9ypAÇed.‘L×Although“the“domains“for“ab-Ž¡’õºâstract–uv‘ÿ|ralues“are,›[¼strictly“spAÇeaking,˜di erenš¾9t“from“con˜textŽ¡’õºâdomains,›£Âw¾9e–‡]will“ignore“abstract“v‘ÿ|ralue“domains.‘íInstead,˜w¾9eŽ¡’õºâonly–“ýconsider“con¾9text“domains,‘³§henceforth“referred“to“sim-Ž¡’õºâply–Tas“ëNdomainsº,‘Tand“pretend“that“for“eac¾9h“domain“there“isŽ¡’õºâa–Tfamily“of“con¾9texts,“and“a“family“of“abstract“v‘ÿ|ralues.ަ’õºâF‘ÿ:«or–Z}eacš¾9h“Milner-Hindley“t˜ypšAÇe,‘kÇthere“is“a“corresp˜onding“do-Ž¡’õºâmain.‘}+In–5’general,‘=¢there“maš¾9y“bAÇe“man˜y“di eren˜t“t˜ypAÇes“whic˜hŽ¡’õºâmap–´Üto“the“same“domain.‘ûThe“next“section“de nes,‘ܾinfor-Ž¡’õºâmally–ÿ:«,‘Ä‘this›°`mapping.‘úÉW“e˜then˜re ne˜the˜mapping˜sligh¾9tly˜inŽ¡’õºâsection–T2.2.4,“and“formalise“it“in“section“2.2.5.Ž©5’õºâ¹2.2Ž’ G·Domains–LÎfoš¹™r“p˜rojection“analysisŽŸm’õºâºA‘@primary–@*aim“of“these“analyses“is“to“generate“informationŽ¡’õºâuseful–Õúfor“exploiting“a“parallel“macš¾9hine.‘RT‘ÿ:«o“this“end,‘â¦w˜e“useŽ¡’õºâdomains–9³whicš¾9h“are“bAÇest“view˜ed“as“a“generalisation“of“theŽ¡’õºâev‘ÿ|raluation–âétransformers“inš¾9troAÇduced“b˜y“Burn“[Bur87Ž‘Žã].‘ ¢TheseŽ¡’õºâare–Tinš¾9troAÇduced“b˜y“example.ަ’õºâ¹2.2.1Ž’úíBase‘LÎt¹™ypFfesŽŸm’õºâºBase–¥ˆt¾9ypšAÇes“ëMInt“ºand“ëMChar“ºare“mapp˜ed“to“a“t•¾9w“o‘¥ˆp˜oin“t‘¥ˆdomainŽ¡’õºâëM2–¹–=“{0,“1}º,‘Ú8with–²ØëM0“ºmeaning“\do“not“ev‘ÿ|raluate“this"“and“ëM1Ž¡’õºâºmeaning–n·\ev›ÿ|raluate“fully".‘äæIn“this“case“only‘ÿ:«,‘ full“ev˜aluation“isŽ¡’õºâthe–§Usame“as“ev‘ÿ|raluation“to“w¾9eak“head“normal“form“(WHNF).ަ’õºâ¹2.2.2Ž’úíNon-recursive–LÎstructured“t¹™ypFfesŽŸm’õºâºConsider–DÕthe“inš¾9terpretation“of“a“familiar“non-recursiv˜e“struc-Ž¡’õºâtured–mBt¾9ypšAÇe:‘ÌMëM(Int,‘¹–Int)º.‘$;W‘ÿ:«e“need“to“mo˜del“the“ev‘ÿ|raluatorsŽ¡’õºâfor–¤the“compAÇonenš¾9ts“of“the“pair“separately‘ÿ:«,‘øso“there“m˜ust“bAÇeŽ¡’õºâa–ÃprošAÇduct“in•¾9v“olv“ed:‘wÿëM(2–¹–x“2)º.‘%ÆAn–Ãev‘ÿ|raluator“corresp˜ondingŽŽŽŽŽŸ’çjã3ŽŽŒ‹<à•ºâ ý? £ ý€‘íºâºto–AØanš¾9y“suc˜h“pAÇoin˜t“w˜ould“ rst“ha˜v˜e“to“ev‘ÿ|raluate“the“pair“clo-ޤ ‘íºâsure–~ëto“WHNF,“so“it“could“get“its“hands“on“the“individualŽ¡‘íºâcompAÇonen•¾9ts.‘ ÕSo›à„w“e˜really˜need˜a˜ fth˜pAÇoin“t˜represen“ting˜anŽ¡‘íºâev‘ÿ|raluator–õˆwhicš¾9h“doAÇes“nothing“at“all.‘×The“o˜v˜erall“in˜terpreta-Ž¡‘íºâtion–Tis“ëMLift–¹–(2“x“2)º.ŽŸ ‘íºâAš¾9t–Fóthis“pAÇoin˜t“it“is“con˜v˜enien˜t“to“in˜troAÇduce“a“notation“forŽ¡‘íºâpšAÇoin¾9ts–çåto“b˜e“used“throughout“this“pap˜er.‘ KThe“b˜ottom“p˜oin¾9tŽ¡‘íºâof–¶the“abAÇo•¾9v“e–¶domain“is“written“as“an“underscore,‘UÎëM_º.‘•TheŽ¡‘íºâother–¼·four“are“written“in“the“form“ëMU[x,‘¹–y]“ºwhere“the“ëMUŽ¡‘íºâºstands–\Vfor“\go“up“the“ëMLiftº",‘Vand“the“ëMx“ºand“ëMy“ºare“the“relev‘ÿ|ran¾9tŽ¡‘íºâpro•AÇduct›»comp“onen•¾9ts.‘5¥The˜o“v“erall˜collection˜of˜ev‘ÿ|raluators˜isŽ¡‘íºâth¾9us–ZVwritten“ëM{_,–¹–U[0,0],“U[0,1],“U[1,0],“U[1,1]}‘ZVºwithŽ¡‘íºâthe–Tfollo¾9wing“ordering:Ž©ÐO‘_ òëMU[1,1]Ž¡‘Zg\/‘Y„\Ž¡‘> ØU[0,1]‘%̰U[1,0]Ž¡‘Zg\\‘Y„/Ž¡‘_ òU[0,0]Ž¡‘mM´|Ž¡‘mM´_ަ‘íºâºHoš¾9w– \doAÇes“this“generalise“to“arbitrary“non-recursiv˜e“struc-Ž¡‘íºâtured›%t•¾9ypAÇes?‘K¢W‘ÿ:«ell,‘(þv“ery˜simply‘ÿ:«.‘K¢A‘% non-recursiv“e˜structuredŽ¡‘íºât¾9ypšAÇe–ŽÆis“mo˜delled“b¾9y“the“single“lifting“of“the“pro˜duct“of“what-Ž¡‘íºâevš¾9er–=Fits“t˜ypšAÇe“v‘ÿ|rariables“are“b˜ound“to.‘”GF‘ÿ:«urther“details“are“ir-Ž¡‘íºârelev‘ÿ|ranš¾9t.‘3That's–ÇŽbAÇecause“w˜e“observ˜e“the“guiding“rule“thatŽ¡‘íºâall–ãÂob‘ƒŽjects“correspšAÇonding“to“a“particular“t¾9yp˜e“v‘ÿ|rariable“areŽ¡‘íºâtreated–6ïas“a“single“en•¾9tit“y‘ÿ:«.‘AThis–6ïrule“is“impAÇosed“for“the“pur-Ž¡‘íºâpAÇose–…of“kš¾9eeping“things“reasonably“straigh˜tforw˜ard.‘k°F‘ÿ:«or“ex-Ž¡‘íºâample,‘Tgiv¾9en:ަ‘ûç¤ëMdata–¹–Foo“a“b“=“MkFoo“a“bŽ¡‘9TB|–¹–MkA“aŽ¡‘9TB|–¹–MkB“bŽ¡¡‘ûç¤data–¹–Grok“a“b“c“=“MkGrok“a“b“cŽ¡‘G|–¹–GrokodileDundee“a“a“a“b“b“cަ‘íºâºa–±~v‘ÿ|ralue“of“ëM(Foo–¹–Int“Int)–±~ºis“mappAÇed“to“ëMLift–¹–(2“x“2)º,Ž¡‘íºâand›S­ëM(Grok–¹–Int“Int“Int)˜ºto˜ëMLift“(2“x“2“x“2)º.‘ ×|MoreŽ¡‘íºâcomplicated–{parameterisations“giv¾9e“rise“to“more“com-Ž¡‘íºâplicated–щdomains.‘ QThe“t¾9ypAÇe“ëM(Grok–¹–Int“(Foo“Int“Int)Ž¡‘íºâ(Grok–¹–Int“Int“Int))–i®ºhas“a“91“pAÇoin¾9t“domainŽ¡‘íºâëMLift–¹–(2“x“Lift“(2“x“2)“x“Lift“(2“x“2“x“2))º.ŽŸ ‘íºâIt–úKis“wš¾9orth“understanding“that“the“n˜um˜bšAÇer“of“pro˜duct“com-Ž¡‘íºâpAÇonenš¾9ts–ãýis“equal“to“the“n˜um˜bAÇer“of“t˜ypAÇe“v‘ÿ|rariables,‘§and“en-Ž¡‘íºâtirely–®unrelated“to“the“n•¾9um“bAÇer–®of“parameters“of“an¾9y“partic-Ž¡‘íºâular–g[constructor.‘…A‘gFcon¾9text“ëMU[1,0,0]“ºapplied“to“an“ob‘ƒŽjectŽ¡‘íºâof–µt¾9ypAÇe“ëM(Grok–¹–Int“Int“Int)–µºmeans:‘)1ev‘ÿ|raluate“the“ob‘ƒŽject“toŽ¡‘íºâthe–·| rst“constructor.‘çThen,›àif“it“is“a“ëMMkGrokº,˜ev‘ÿ|raluate“theŽ¡‘íºâ rst–{5argumenš¾9t.‘NOtherwise,‘”­it“m˜ust“bAÇe“a“ëMGrokodileDundeeº,Ž¡‘íºâso–&Eev‘ÿ|raluate“the“ rst“three“parameters.‘ODW‘ÿ:«e“treat“the“ rstŽ¡‘íºâargumen¾9t–Îto“ëMMkGrok“ºand“the“ rst“three“of“ëMGrokodileDundeeŽ¡‘íºâºas–¸da“single“en•¾9tit“y–¸dbšAÇecause“they“all“corresp˜ond“to“the“sameŽ¡‘íºât¾9ypAÇe–Tv‘ÿ|rariable,“ëMaº,“in“the“declaration.ŽŸ5‘íºâ¹2.2.3Ž‘ úíRecursive–LÎstructured“t¹™ypFfesŽŸm‘íºâºSo–QQfar,‘`Qthings“are“reasonably“straigh•¾9tforw“ard.‘ÐhBut‘QQde ningŽ¡‘íºâev‘ÿ|raluators–1œfor“recursivš¾9e“t˜ypšAÇes“is“a“mine eld,‘8®partly“b˜ecauseŽ¡‘íºâthere–exare“so“manš¾9y“alternativ˜e“form˜ulations“[W‘ÿ:«ad87Ž‘¿˜]“[WH87Ž‘±].Ž¡‘íºâAs–v¸it“happAÇens,‘Ïthe“form¾9ulation“used“in“Anna“is“a“trivialŽŽŽ ý€’õºâv‘ÿ|rariation–JÕof“the“rule“for“non-recursivš¾9e“t˜ypAÇes,‘sUbut“justi cationޤ ’õºâis–Tnot“so“easy‘ÿ:«.ŽŸ ’õºâThe–#§rule“is“idenš¾9tical“to“the“non-recursiv˜e“case,‘g;except“forŽ¡’õºâthe–ïÖfollo¾9wing“mošAÇdi cation:‘ ±the“single“lifting“of“the“pro˜duct,Ž¡’õºâwritten–¥+ëMLiftº,›É is“replaced“b¾9y“a“double“lifting,˜ëMLift2º.‘ËõNo¾9w,Ž¡’õºâgiv¾9en–Tthe“pseudo-declarationŽ©ÐO’ç¤ëMdata–¹–[a]“=“[]Ž¡’.mê|–¹–a“:“[a]ަ’õºâºit–Tis“easy“to“see“that“the“domain“for“ëM[Int]“ºis“ëMLift2‘¹–(2)º,‘c¶aŽ¡’õºâfour–‰@pšAÇoin¾9t“domain“corresp˜onding“precisely“to“the“in¾9terpreta-Ž¡’õºâtion–for“that“tš¾9ypAÇe“made“b˜y“W›ÿ:«adler“[W˜ad87Ž‘¿˜]“and“later“justi-Ž¡’õºâ ed–!b¾9y“Burn“[Bur87Ž‘Žã].‘ËExtending“the“notation“of“the“previousŽ¡’õºâsection,‘Dqwš¾9e–7write“the“pAÇoin˜ts“in“this“domain“as“ëM{_,–¹–U_,“UU[0]Ž¡’õºâºand–Ý®ëMUU[1]}º,‘Äunderstanding“them“to“denote“the“ev‘ÿ|raluatorsŽ¡’õºâwhic¾9h–TBurn“called“ëM{E0,–¹–E1,“E2–Tºand“ëME3}º:ަ’äëPŽŽŽ’ :âëM_º:‘pDo–Tnot“ev‘ÿ|raluate“at“all“(ëME0º).Ž©34’äëPŽŽŽ’ :âëMU_º:‘¹Ev‘ÿ|raluate–æas“far“as“the“ rst“constructor,›üthat“is,˜toŽ¡’ :âw¾9eak–Thead“normal“form“(ëME1º).ަ’äëPŽŽŽ’ :âëMUU[0]º:‘pEv‘ÿ|raluate–Tthe“en¾9tire“structure“of“the“list“(ëME2º).ަ’äëPŽŽŽ’ :âëMUU[1]º:‘˺Ev‘ÿ|raluate–ìùthe“en¾9tire“structure“of“the“list,‘"âandŽ¡’ :âall–Tthe“elemen¾9ts“(ëME3º).ŽŸÐO’õºâIn–T“general,‘{!a“recursivš¾9e“t˜ypAÇe“of“ëMn“ºparameters“has“ev‘ÿ|raluators“ofŽ¡’õºâthe–þ form“ëM{_,›¹–U_“ºand“ëMUU[x1˜...˜xn]}º.‘­The“ëMUU[x1˜...˜xn]Ž¡’õºâºpAÇoinš¾9ts–O›denote“ev‘ÿ|raluating“the“en˜tire“structure,‘^,and“then“ap-Ž¡’õºâplying–«Hev‘ÿ|raluator“ëMx1“ºto“eac¾9h“ob‘ƒŽject“correspAÇonding“to“the“ rstŽ¡’õºâparameter,‘WëMx2–¬ºto“ob‘ƒŽjects“correspAÇonding“to“the“second“pa-Ž¡’õºârameter,›³Cand–`zso“on.‘ýâW‘ÿ:«e“will“see,˜in“Section“4,˜that“thisŽ¡’õºâconceptual–¸partitioning“of“all“recursivš¾9e“domain“pAÇoin˜ts“in˜toŽ¡’õºâthree–ž#sections“is“crucial“to“the“w¾9orking“of“the“term“rewritingŽ¡’õºâsystem–œbused“to“detect“ xpAÇoinš¾9ts.‘ôSimilarly‘ÿ:«,‘´“the“non-recursiv˜eŽ¡’õºâpAÇoin•¾9ts›¼ãma“y˜bAÇe˜partitioned˜in“to˜t“w“o:‘ð7ëM{_˜ºand˜ëMU[x1–¹–...“xn]}º.Ž© ’õºâThe–ºguiding“principle,›#>originally“stated“b¾9y“W‘ÿ:«adler,˜is“toŽ¡’õºâmoAÇdel–“tthe“recursivš¾9e“t˜ypAÇes“b˜y“letting“the“sub-ev‘ÿ|raluatorsŽ¡’õºâin–')ëMUU[...]“ºv‘ÿ|ralues“bAÇe“represen•¾9tativ“e–')of“the“least“de nedŽ¡’õºâelemenš¾9t–óèof“that“t˜ypAÇe“in“the“structure.‘¸,Imagine“w˜eŽ¡’õºâha•¾9v“e–©Õa“list“of“tš¾9ypAÇe“ëM[(Int,‘¹–Int)]º,‘Žôwhic˜h“induces“do-Ž¡’õºâmain›ªvëMLift2–¹–(Lift“(2“x“2))º,‘Ͼand˜w•¾9e˜kno“w˜that˜ev‘ÿ|raluatorŽ¡’õºâëMUU[U[0,1]]–°Ÿºis“the“strongest“that“can“safely“bAÇe“applied“(thatŽ¡’õºâis,‘mwithout–³danger“of“non-termination)“to“the“list.‘õzNo¾9wŽ¡’õºâsuppAÇose–Âwš¾9e“obtain“another“list“for“whic˜h“ëMUU[U[1,0]]“ºis“theŽ¡’õºâstrongest–ßsafe“ev‘ÿ|raluator,‘MÄand“appAÇend“it“to“the“original.‘ÉIWhatŽ¡’õºâis–ôHthe“bšAÇest“ev‘ÿ|raluator“that“can“b˜e“applied“to“the“new“list?Ž¡’õºâIt–O}cannot“bAÇe“either“of“the“originals,‘žsince“that“risks“non-Ž¡’õºâtermination.‘'HThe–nGmost“wš¾9e“can“ev‘ÿ|raluate“an˜y“particular“ele-Ž¡’õºâmen¾9t–luwhilst“remaining“safe“is“ëMU[0,0]º,‘‚=so“the“bAÇest“that“canŽ¡’õºâbAÇe–applied“to“the“list“as“a“whole“is“ëMUU[U[0,0]]“º{“the“great-Ž¡’õºâest›fÉlo•¾9w“er˜bAÇound˜of˜the˜v‘ÿ|ralues˜for˜the˜original˜lists.‘ÏW‘ÿ:«adlerŽ¡’õºâsummarised–”Sthis“bš¾9y“stating“that“a“list“is“c˜haracterised“\b˜yŽ¡’õºâits–¦Ùleast“de ned“elemenš¾9t"“but“w˜e“need“to“bAÇe“more“precise:Ž¡’õºâa–— list“is“cš¾9haracterised“b˜y“the“greatest“ev‘ÿ|raluator“that“canŽ¡’õºâsafely–D•bAÇe“applied“to“anš¾9y“elemen˜t,‘Peev˜en“if“a“stronger“ev‘ÿ|ralua-Ž¡’õºâtor–Icould“bšAÇe“applied“to“sp˜eci c“elemen¾9ts.‘Ø~The“same“principleŽ¡’õºâgeneralises–SÔto“structured“tš¾9ypAÇes“of“an˜y“n˜um˜bAÇer“of“parameters,Ž¡’õºâwith–^the“greatest-lo•¾9w“er-bAÇound›^c“haracterisation˜oAÇccurring˜in-Ž¡’õºâdepAÇendenš¾9tly–Tfor“eac˜h“parameter.ަ’õºâThis–(abstraction,›FËwhilst“simple,˜assumes“that“programs“treatŽ¡’õºâall–ð elemenš¾9ts“of“the“same“t˜ypAÇe“inside“a“structure“in“the“sameŽŽŽŽŽŸ’çjã4ŽŽŒ‹[” •ºâ ý? £ ý€‘íºâºw•¾9a“y–ÿ:«.‘ F“or–åÜexample,‘ï[it“assumes“list“proAÇcessing“functions“treatޤ ‘íºâall–èÍelemenš¾9ts“in“the“list“the“same“w˜a˜y–ÿ:«.‘ ˜F“unctions–èÍnot“pla˜yingŽ¡‘íºâalong–Áwith“this“ma¾9y“induce“bad,›Ñ÷but“safe,˜results.‘^Consider:ޤÐO‘ûç¤ëMtail–¹–(x:xs)“=“xsŽ¡‘íºâºIf–¿^wš¾9e“apply“a“ëMUU[1]“ºev‘ÿ|raluator“to“ëM(tail‘¹–zs)º,‘éàwhat“can“w˜eޤ ‘íºâev‘ÿ|raluate–Œ%ëMzs“ºwith?‘€ãUnfortunately‘ÿ:«,›©Ùnot“ëMUU[1]º,˜since“the“ele-Ž¡‘íºâmenš¾9t–"that“ëMtail“ºthro˜ws“a˜w˜a˜y“migh˜t“just“ha˜v˜e“bAÇeen“the“one-Ž¡‘íºâand-only–¥þnon-terminating“ëMInt“ºin“the“list.‘ÎmErring“on“theŽ¡‘íºâside–ààof“safetš¾9y“th˜us“restricts“the“ev‘ÿ|raluator“for“ëMzs“ºto“ëMUU[0]º,Ž¡‘íºâand–%îloses“all“the“pAÇoten¾9tial“parallelism“in“ev‘ÿ|raluating“the“ele-Ž¡‘íºâmen¾9ts–+in“the“rest“of“the“list.‘3ôOne“upshot“of“this,‘ also“notedŽ¡‘íºâbš¾9y–/RW‘ÿ:«adler,‘uÒis“that“de ning“functions“directly“b˜y“pattern-Ž¡‘íºâmatcš¾9hing– ×is“essen˜tial“to“get“go•AÇo“d– ×results.‘ùúIn“the“exampleŽ¡‘íºâbAÇeloš¾9w,‘Âthe–­1analyser“giv˜es“a“m˜uc˜h“bAÇetter“result“for“ëMsum1“ºthanŽ¡‘íºâëMsum2º,–Tdespite“them“haš¾9ving“iden˜tical“strictness“propAÇerties.Ž©ÐO‘ûç¤ëMsum1–¹–[]‘Y„=“0Ž¡‘ûç¤sum1–¹–(x:xs)‘ s,=“x“+“sum1“xsŽ¡¡‘ûç¤sum2–¹–xs‘Y„=“if‘æXnull“xsŽ¡‘BÇnthen‘ s,0Ž¡‘BÇnelse‘ s,head–¹–xs“+“sum2“(tail“xs)ަ‘íºâºA‘áórelated–âdefect“is“the“inabilit¾9y“of“these“domains“to“captureŽ¡‘íºâthe–K@notion“of“head“strictness.‘¾3A‘K2head“strict“function“is“oneŽ¡‘íºâwhicš¾9h–Æ>ev‘ÿ|raluates“the“ rst“item“in“a“list“whenev˜er“it“ev‘ÿ|raluatesŽ¡‘íºâthe– 'list“as“far“as“the“ rst“constructor,‘IÛand“disco•¾9v“ers– 'it“toŽ¡‘íºâbAÇe–‹non-nil.‘}ªHead“strictness“is“useful“in“a“sequen¾9tial“imple-Ž¡‘íºâmen¾9tation,‘so–îan“extension“of“the“domains“to“capture“theseŽ¡‘íºâpropšAÇerties–Tw¾9ould“increase“the“useful“scop˜e“of“this“analyser.Ž©5‘íºâ¹2.2.4Ž‘ úíMoFfdifying–LÎthe“notationŽŸm‘íºâºThe›,ÀabAÇo•¾9v“e˜mapping˜assigns˜domain˜ëMLift‘¹–()˜ºto˜allŽ¡‘íºâen•¾9umeration› ¹At“ypAÇes,‘ b:for˜example˜the˜familiar˜t“ypAÇeŽ¡‘íºâëMdata–¹–Bool“=“False“|“Trueº.‘<Since“the“domain“has“91“pAÇoinš¾9ts,‘Ôit“w˜ouldŽ¡‘íºâappšAÇear–rnecessary“to“compile“90“v¾9ersions“of“the“co˜de,‘™ùomit-Ž¡‘íºâting–çêthe“v¾9ersion“for“no“demand“at“all“on“the“output.‘ MBurn'sŽ¡‘íºâearly–‡wš¾9ork“simply“ignored“the“problem“b˜y“restricting“itselfŽ¡‘íºâto–ó¶lists“of“ëMIntº,‘+Nfor“whic¾9h“at“most“3“copies“of“coAÇde“are“re-Ž¡‘íºâquired.‘7aQuite–Èúwhat“to“do“abšAÇout“complex“t•¾9yp˜es,‘õãwhic“h‘Èúin-Ž¡‘íºâduce–.ÃproAÇduct“domains,‘5or“non-trivial“instan¾9tiations“of“lists,Ž¡‘íºâis–Tnot“clear.ަ‘íºâThis–½unsatisfactory“state“of“a airs“can“to“some“exten¾9t“bAÇeŽ¡‘íºâalleviated–·bš¾9y“restricting“ourselv˜es“to“compiling“just“a“subsetŽŽŽ ý€’õºâof–"Üall“the“pAÇossible“vš¾9ersions“of“eac˜h“function.‘EThen,‘f=whenޤ ’õºâthe–Ëîoutput“of“a“function“is“demanded“in“a“conš¾9text“for“whic˜hŽ¡’õºâno–ë½vš¾9ersion“has“bAÇeen“compiled,‘ôthe“v˜ersion“used“is“that“com-Ž¡’õºâpiled–kafor“the“greatest“demand“less“than“the“demand“w¾9e“re-Ž¡’õºâquired.‘­«Observš¾9e–E½that“the“c˜hoice“of“alternativ˜e“is“not“neces-Ž¡’õºâsarily›3unique,–`Qbut,“pro•¾9vided˜w“e˜compiled˜in˜a˜fully˜sequen“tialŽ¡’õºâ(that–4Õis,›<¶WHNF‘4Ídemand)“v¾9ersion,˜an“alternativ¾9e“is“at“leastŽ¡’õºâguaranš¾9teed–±9to“exist.‘ðOf“course,‘Ø2some“pAÇoten˜tial“parallelismŽ¡’õºâma•¾9y›˜w“ell˜bAÇe˜lost:‘!Ïsuc“h˜is˜the˜price˜for˜restricting˜the˜coAÇdeŽ¡’õºâexplosion–Tto“a“tolerable“magnitude.Ž© ’õºâThe–FØcenš¾9tral“question,–p%then,“is–FØwhic˜h“v˜ersions“to“compile“coAÇdeŽ¡’õºâfor.‘NoOne–{TpAÇerson“who“has“v•¾9en“tured›{Tin“to˜this˜quagmire˜isŽ¡’õºâMin•¾9tc“hev.‘£F‘ÿ:«or–Çìhis“MSc“dissertation“[Min92Ž‘o™],‘×gMin•¾9tc“hev‘ÇìbuiltŽ¡’õºâa–á@simš¾9ulation“of“a“parallel“graph“reduction“mac˜hine,‘;whic˜hŽ¡’õºâunderstands–áthree“levš¾9els“of“demand:‘6none“at“all,‘ Åw˜eak“headŽ¡’õºânormal–gÊform“demand,‘|gand“full“demand.‘ÑAn“immediate“ad-Ž¡’õºâv‘ÿ|ranš¾9tage–Ùlis“that“these“pAÇoin˜ts“apply“to“all“structured“t˜ypAÇes,Ž¡’õºâincluding–!Ôtuples“and“complex“instanš¾9tiations“of“t˜ypAÇes,‘Rˆand“areŽ¡’õºâthš¾9us–¨¢more“widely“applicable“than“Burn's“sc˜heme.‘Ö[Encour-Ž¡’õºâagingly‘ÿ:«,›ï$ev¾9en–Ôwith“so“few“ev‘ÿ|raluators,˜Min•¾9tc“hev–Ôfound“thatŽ¡’õºâsubstan•¾9tial›¿–amoun“ts˜of˜parallel˜activit“y˜w“ere˜generated,‘мv‘ÿ|ral-Ž¡’õºâidating–·&his“approac•¾9h.‘åRecen“tly–·&it“has“bAÇeen“suggested“thatŽ¡’õºâa–#Ófourth“ev›ÿ|raluator“migh¾9t“bAÇe“pro tably“included:‘9nev˜aluationŽ¡’õºâof–ýKthe“enš¾9tire“structure“of“a“recursiv˜e“t˜ypAÇe,‘7Ibut“no“ev‘ÿ|ralua-Ž¡’õºâtion–M of“the“compAÇonenš¾9ts.‘ÅSThis“mak˜es“no“sense,›[³of“course,˜inŽ¡’õºâa–YTnon-recursivš¾9e“t˜ypAÇe,–jTor,“alternativ˜ely‘ÿ:«,“one–YTcan“regard“it“asŽ¡’õºâequiv›ÿ|ralen¾9t–Tto“the“WHNF“ev˜aluator,“in“this“case.ަ’õºâA‘.öfurther–/Äcomplication“is“what“to“do“abšAÇout“p˜olymor-Ž¡’õºâphic–‡­functions.‘ s|W‘ÿ:«e“maš¾9y“compile“three“v˜ersions“of“theŽ¡’õºâëMreverse–ª ºfunction,‘Ï:w¾9orking“from“the“ev‘ÿ|raluators“of“the“sim-Ž¡’õºâplest–…Ÿinstance,‘¡±but“then“what“do“wš¾9e“do“giv˜en“an“ev‘ÿ|raluatorŽ¡’õºâëMUU[U[1,0]]–G*ºapplied“to“a“use“of“ëMreverse“ºat“non-base“instanceŽ¡’õºâëM[(Int,–¹–Int)]“->“[(Int,“Int)]º?‘aêSuce–,}it“to“sa¾9y“that“aŽ¡’õºâpšAÇossible–solution“is“only“to“compile“v¾9ersions“of“p˜olymorphicŽ¡’õºâfunctions–ð½based“on“their“ev‘ÿ|raluators“for“simplest“instances,Ž¡’õºâand–Âause“safe“approš¾9ximation“tec˜hniques“based“on“Conc“mapsŽ¡’õºâto–ä`handle“the“non-base“instances.‘ See“[HH91Ž‘>],›î*section“5,˜forŽ¡’õºâan–@–in¾9troAÇduction“to“Conc“maps.‘Õ†My“MSc“dissertation“[Sew91Ž‘/]Ž¡’õºâindicates–#­ho¾9w“Conc“maps“are“useful“in“matters“of“pAÇolymor-Ž¡’õºâphism,–Ta“theme“explored“further“in“[Sew93Ž‘/].ަ’õºâNoš¾9w,‘ê¹if–àthe“compiler“is“only“going“to“mak˜e“coAÇde“for“a“few“ofŽ¡’õºâall– äthe“pAÇossible“ev‘ÿ|raluators“for“a“function“returning“an“ob‘ƒŽjectŽ¡’õºâof–)bcomplex“t¾9ypšAÇe,‘.fwhat“is“the“p˜oin¾9t“of“doing“strictness“anal-Ž¡’õºâysis–UÛwith“the“full“complemen¾9t“of“ev‘ÿ|raluators?‘ÞAfter“all,‘eüthisŽ¡’õºâamounš¾9ts–×ato“doing“a“detailed“analysis,‘åthen“thro˜wing“a˜w˜a˜yŽ¡’õºâmost–çof“the“detail“in“the“ nal“answš¾9er.‘÷)It“w˜ould“certainlyŽ¡’õºâbAÇe›JØm•¾9uc“h˜quic“k“er˜just˜to˜w“ork˜with˜those˜few˜ev‘ÿ|raluators˜w“eŽ¡’õºâare–—\really“inš¾9terested“in.‘òsNev˜ertheless,‘°Ždoing“that“risks“losingŽ¡’õºâin¾9termediate‘ˆ°detail,–¥‡and,“ultimately‘ÿ:«,“parallelism,“comparedŽ¡’õºâwith––/the“expAÇensivš¾9e“approac˜h.‘òBuilding“an“abstract“in˜terpre-Ž¡’õºâtation–gXfor“the“el“cš¾9heapAÇo“approac˜h“migh˜t“also“bAÇe“rather“dif-Ž¡’õºâ cult,‘;and–sthe“inš¾9terpreter“w˜ould“ha˜v˜e“to“bAÇe“rewritten“ev˜eryŽ¡’õºâtime–™®the“particular“subset“of“inš¾9teresting“ev‘ÿ|raluators“c˜hanged.ަ’õºâA‘‘x nal–‘™inš¾9teresting“ca˜v˜eat“pAÇertains“to“higher-order“functions.Ž¡’õºâAs–6Üexplained“to•¾9w“ards–6Üthe“end“of“section“1.2,‘=it“loAÇoks“dif-Ž¡’õºâ cult–Ä4to“exploit“parallelism“in“higher-order“functions“if“w¾9eŽ¡’õºâdo–é†not“w•¾9an“t–é†to“engage“in“complicated“manipulation“of“ev‘ÿ|ral-Ž¡’õºâuation–˜¬transformers“at“run-time.‘¦xOne“can“therefore“rea-Ž¡’õºâsonably–ÈÞargue“that“the“higher-order“remo¾9v‘ÿ|ral“transformationŽ¡’õºâ( rsti cation)–ždescribAÇed“in“section“5“enhances“parallelism.Ž¡’õºâWhat–& rsti cation“doAÇes“is“to“disco•¾9v“er–&statically“some“of“theŽ¡’õºâfunctional–Èparameters“passed“to“higher-order“functions,‘ÓäandŽ¡’õºâspAÇecialise–;them“accordingly‘ÿ:«,‘Ltgenerating“ rst-order“replace-ŽŽŽŽŽŸ’çjã6ŽŽŒ‹“§ •ºâ ý? £ ý€‘íºâºmenš¾9ts.‘KøThese–Ï×can“then“bAÇe“parallelised“in“the“normal“w˜a˜y‘ÿ:«,ޤ ‘íºâwithout–8Vhaš¾9ving“to“resort“to“complicated“run-time“mac˜hinery‘ÿ:«.Ž¡‘íºâMa¾9ybšAÇe,–Ô¦then,“this–Äztransformation“should“b˜e“incorp˜orated“asŽ¡‘íºâa–Tmatter“of“course“in¾9to“go•AÇo“d–Tparallelising“compilers.ŽŸ-‘íºâ¹3Ž‘ü”The–LÎabstract“interp¹™retationŽŸ†´‘íºâ3.1Ž‘G·Prelimina¹™riesޤm‘íºâ3.1.1Ž‘ úíThe–LÎnotion“of“fo•¹™rw“a“rds–LÎand“backw•¹™a“rdsŽ¡‘íºâºSemanš¾9tic–`êanalyses“of“functional“languages“seem“to“fall“in˜toޤ ‘íºât•¾9w“o›Ôvcamps:‘š³forw“ards˜and˜bac“kw“ards.‘YÕT‘ÿ:«o˜see˜the˜in“tuitiv“eŽ¡‘íºâmeaning–Tof“this,“consider“a“function“application:ޤÐO‘ûç¤ëM(f–¹–x“y“z)Ž¡‘íºâºA‘èforwš¾9ard–è‡analysis“generates“information“abAÇout“ëMf“ºwhic˜hޤ ‘íºâtells–MÑus“propAÇerties“of“the“application“ëM(f–¹–x“y“z)–MѺif“wš¾9e“kno˜wŽ¡‘íºâthe–¤epropAÇerties“of“the“individual“argumen¾9ts,–È)ëMxº,“ëMy–¤eºand“ëMzº.‘ɤInŽ¡‘íºâother–Ùšw¾9ords,‘ ¬the“analysis“propagates“information“óR¼j‘¹ cmti9ëRforwar‡dsŽ¡‘íºâºthrough–ªµfunctions.‘Ü“F‘ÿ:«orw¾9ard“analyses“tend“to“bšAÇe“exp˜ensiv¾9eŽ¡‘íºâbšAÇecause–зthey“ha•¾9v“e–зto“consider“all“p˜ossible“in¾9teractions“b˜e-Ž¡‘íºât•¾9w“een›²¢argumen“ts.‘ô[On˜the˜other˜hand,‘Ùöone˜gets˜a˜v“ery˜de-Ž¡‘íºâtailed–Tpicture“of“what“is“going“on.Ž© ‘íºâA‘ù§bac•¾9kw“ard›ú$analysis,‘sXb“y˜con“trast,‘sXgenerates˜informationŽ¡‘íºâabšAÇout–ÑúëMf“ºwhic¾9h“tells“us“the“prop˜erties“of“the“individual“argu-Ž¡‘íºâmenš¾9ts–HŒëMxº,‘qëMy“ºand“ëMz“ºif“w˜e“kno˜w“some“propAÇert˜y“of“the“applicationŽ¡‘íºâëM(f–¹–x“y“z)º.‘ñThat– ×is,‘Va“bac•¾9kw“ards– ×analysis“propagates“prop-Ž¡‘íºâerties›®4ëRb•‡ackwar“ds˜ºthrough˜functions.‘úBac•¾9kw“ard˜analyses˜ma“yŽ¡‘íºâb•AÇe›2Ÿc¾9heap“er˜to˜do,‘_÷but˜they˜ma•¾9y˜also˜giv“e˜less˜detailed˜results.ަ‘íºâNoš¾9w,‘åfor–ÙŒreasons“whic˜h“will“shortly“bAÇecome“apparen˜t,‘åAnnaŽ¡‘íºâdoAÇes–Åua“comš¾9bined“forw˜ard“and“bac˜kw˜ard“analysis.‘ÐThe“prop-Ž¡‘íºâerties–\>whicš¾9h“Anna“propagates“forw˜ards“through“functionsŽ¡‘íºâare–{the“abstract“v‘ÿ|ralues,‘”‡whilst“those“whicš¾9h“ o˜w“bac˜kw˜ardsŽ¡‘íºâare–h conš¾9texts.‘â®T‘ÿ:«o“set“the“stage,‘жobserv˜e“critically“that“ëRAÃŽnna'sŽ¡‘íºâmain–¥±purpš‡ose“is“to“determine“the“b˜ackwar˜ds“b˜ehaviour“ofŽ¡‘íºâthe›sour•‡c“e˜language˜functionsº.‘ÒThe–Èzpresence“of“forw¾9ard“(ab-Ž¡‘íºâstract)–÷ v‘ÿ|ralues“is“a“necessary“evil“whic¾9h“enables“us“to“dealŽ¡‘íºâcleanly–Ú[with“higher-order“functions.‘k†The“discussion“whic¾9hŽ¡‘íºâno•¾9w›sæfollo“ws˜mak“es˜more˜sense˜if˜y“ou˜k“eep˜a˜clear˜notion˜thatŽ¡‘íºâabstract–=xv‘ÿ|ralues“correspAÇond“to“a“forwš¾9ards“ o˜w“of“information,Ž¡‘íºâwhilst–Tconš¾9texts“correspAÇond“to“a“bac˜kw˜ards“ o˜w.ŽŸ5‘íºâ¹3.1.2Ž‘ úíA–LÎfundamental“pš¹™roblem“with“backw˜a˜rds“analysisŽŸm‘íºâºBac•¾9kw“ards–Ø.strictness“analysis“wš¾9ould“bAÇe“straigh˜tforw˜ard,Ž¡‘íºâw¾9ere–_˜it“not“for“the“higher-order“nature“of“the“language“underŽ¡‘íºâanalysis.‘pT‘ÿ:«o–Tsee“the“problem,“consider“ëMapplyº:ޤÐO‘ûç¤ëMapply–¹–f“x“=“f“xŽ¡‘íºâºGiv¾9en–hôsome“demand“on“a“use“of“apply‘ÿ:«,›}ÜëM(apply–¹–g“y)º,˜whatޤ ‘íºâdemand– [maš¾9y“bAÇe“propagated“to“ëMyº?‘…Without“kno˜wing“ho˜wŽ¡‘íºâëMg–8ºpropagates“demand“to“its“argumenš¾9t,‘1the“only“safe“answ˜erŽ¡‘íºâis›E\none".‘«‡Ho•¾9w“ev“er,‘òkno“wing˜what˜ëMg˜ºis˜implies˜ha“ving˜aŽ¡‘íºâforw•¾9ard›áµ o“w˜of˜information,‘ìas˜w“ell˜as˜the˜bac“kw“ard˜ o“w˜ofŽ¡‘íºâdemand–Tw¾9e“started“with.ަ‘íºâThings–º«loAÇok“grimmer“when“w¾9e“put“functions“inside“dataŽ¡‘íºâstructures,–Tthen“ sh“them“out“and“apply“them:ŽŸÐO‘ûç¤ëM1–¹–+“(head“xs“(y+1))ŽŽŽ ý€’õºâºwhere›½åëMxs–¹–::“[Int“->“Int]º.‘$There˜is˜no˜w•¾9a“y˜to˜tell˜whatޤ ’õºâdemand–Tcould“bAÇe“propagated“to“ëMyº.Ž© ’õºâThe–ísolution“really“lies“in“building“a“comš¾9bined“bac˜kw˜ardsŽ¡’õºâand–¯×forwš¾9ards“analysis.‘ëøW‘ÿ:«ra˜y“[W‘ÿ:«ra85Ž‘:C]“made“a“start“on“theŽ¡’õºâproblem,‘Yÿbut–LDit“toAÇok“the“w¾9ork“of“Hughes“[Hug87Ž‘ó']“to“gener-Ž¡’õºâalise–O‰W‘ÿ:«raš¾9y's“results“to“the“pAÇoin˜t“of“general“applicabilit˜y‘ÿ:«.‘Ú‚TheŽ¡’õºâresulting–÷˜analysis“is“rather“hard“to“understand,–0)so,“ratherŽ¡’õºâthan–ˆ×attempting“a“head-on“assault,‘¥¸w¾9e“loAÇok“ rst“at“under-Ž¡’õºâlying–Tissues,“starting“o “with“some“new“concepts.ŽŸºç’õºâ¹3.2Ž’ G·F¹™unction‘LÎcontextsŽŸm’õºâºDealing–-øwith“functions“propAÇerly“means“turning“them“in¾9toŽ¡’õºâ rst-class–Âlcitizens“for“the“purpAÇoses“of“the“abstract“in¾9ter-Ž¡’õºâpreter.‘‰Section–ž2.2“discussed“the“notion“of“demand“(or“con-Ž¡’õºâtext)–Q/on“a“data“structure.‘ÐW‘ÿ:«e“no¾9w“extend“the“notion“ofŽ¡’õºâcon¾9text–Tto“functions.ަ’õºâSince– Êa“con¾9text“really“denotes“a“demand“for“ev‘ÿ|raluation,‘ ætheŽ¡’õºâidea–¶ of“a“function“conš¾9text“seems“prett˜y“meaningless:‘]ßafterŽ¡’õºâall,‘¹§hoš¾9w–˜Écan“a“function“bAÇe“ev‘ÿ|raluated?‘¦ÐBut“imagine“w˜e“de-Ž¡’õºâ ned–¼#a“function“conš¾9text“as“a“pair,‘å×con˜taining“the“abstractŽ¡’õºâv‘ÿ|ralue–RÚof“the“argumenš¾9t,‘bôin“section“2.1.‘™QF‘ÿ:«or“non-function“v‘ÿ|ralues,‘‰\they“areŽ¡’ :âas–“~discussed“in“section“2.2.‘–íF‘ÿ:«or“function“v‘ÿ|ralues,‘³theyŽ¡’ :âare–HÀa“pair“whicš¾9h“w˜e“write“as“ëM(Fnc–¹–a“c)º,‘•šwhere‘HÀëMFncŽ¡’ :âºreminds–æ•that“this“is“a“ëNF‘ÿÌuNction‘}·Con´Ctextº,‘åëMa“ºis“theŽ¡’ :âabstract–¯3v‘ÿ|ralue“of“the“argumenš¾9t“and“ëMc“ºis“the“con˜text“onŽ¡’ :âthe–9 result.‘‡‘Henceforth,‘A÷v‘ÿ|rariables“denoting“con¾9texts“orŽ¡’ :âconš¾9text–Tmaps“ha˜v˜e“'c'“as“their“ rst“letter.ŽŸ÷Ü’äëPŽŽŽ’ :âëNAbstract‘ @v‘ÿh‰alues–£º(also“called“forw¾9ards“v‘ÿ|ralues).‘ö[TheseŽ¡’ :âare–›¬the“second“kind“of“abstract“en•¾9tit“y–›¬describAÇed“in“sec-Ž¡’ :âtion–ê2.1.‘÷They“are“designed“purely“to“con•¾9v“ey‘êcon“textsŽ¡’ :âto–=^anš¾9y“place“in˜v˜olving“a“call“to“an“unkno˜wn“function,Ž¡’ :âsucš¾9h–‰ôas“in“the“t˜w˜o“problematic“examples“abAÇo˜v˜e.‘zOTheŽ¡’ :âabstract–+v‘ÿ|ralues“of“non-function“ob‘ƒŽjects“are“alw•¾9a“ys‘+irrel-Ž¡’ :âev‘ÿ|ran¾9t–¤ãand“are“mappšAÇed“to“a“1-p˜oin¾9t“domain,‘»`whose“sin-Ž¡’ :âgle–G°pšAÇoin¾9t“is“denoted“ëM#º,‘pÒfor“the“time“b˜eing.‘×äThe“abstractŽŽŽŽŽŸ’çjã7ŽŽŒ‹·7 •ºâ ý? £ ýõ¦dŸÂlΑíºâŸ¾S4‰fföÌ̤ÿþ•ÌÍŸwÙš„~Ù˜ffŸ·32‘8ŸÚŒÍ‰ff†C,¡“¤„ ff‘fg„ ff‘33ŸüÿþºDe ning‘Tequation‘"V¡„ ffŽ‘p·Disassem¾9bles–Ta“...‘"½¤Ÿ„ ffŽ’ß• proAÇducing–Tthe“...‘a˜Ÿ„ ff‘fg„ ffŽŽ©fh‰ff†C,¡“Ÿ„ ff‘fg„ ff‘hæ„ ffŽ’ÙûtŸ„ ffŽ’„C,Ÿ„ ff‘fg„ ffŽŽ¤ “¤„ ff‘fg„ ff‘33ŸüÿþëMFncA› s,(Fnc–¹–a“c)˜=“a‘33¡„ ffŽ‘p·ºfunctional‘Tcon¾9text‘ @OŸ„ ffŽ’ß• abstract–Tv‘ÿ|ralue“of“the“argumen¾9t‘'õ¡Ÿ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff‘33ŸüÿþëMFncC› s,(Fnc–¹–a“c)˜=“c‘33¡„ ffŽ‘p·ºfunctional‘Tcon¾9text‘ @OŸ„ ffŽ’ß• con¾9text–Ton“the“result‘PRŸ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff›33ŸüÿþëMFvalA–¹–(Fval“c“a)“=“a˜¡„ ffŽ‘p·ºfunctional–Tabstract“v‘ÿ|ralue‘33Ÿ„ ffŽ’ß• abstract–Tv‘ÿ|ralue“map:‘pargumen¾9t“to“result‘33Ÿ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff›33ŸüÿþëMFvalC–¹–(Fval“c“a)“=“c˜¡„ ffŽ‘p·ºfunctional–Tabstract“v‘ÿ|ralue‘33Ÿ„ ffŽ’ß• conš¾9text–Tmap:‘presult“to“argumen˜t‘ @OŸ„ ff‘fg„ ffŽŽ¡“Ÿ„ ff‘fg„ ff‘hæ„ ffŽ’ÙûtŸ„ ffŽ’„C,Ÿ„ ff‘fg„ ffŽŽ¦‰ff†C,ŽŽŽŸ;ÌÌ’˜TT‘ÿ:«able–T1:‘pSelector“functions“for“functional“en¾9titiesŽŽŸ Ž’öff„~Ù˜ffŽŽŸx@‰fföÌÌŽŽŽŽ  Yœ þ¦d‘:âv›ÿ|ralue–2&of“a“function-v˜alued“ob‘ƒŽject“is“also“a“pair“(butޤ ‘:âquite–7îunrelated“to“ëMFnc“ºpairs),‘À”written“ëM(Fval–¹–c“a)º,Ž¡‘:âwith–J¡ëMFval“ºreminding“us“this“is“a“ëNF‘ÿÌunctional‘£jabstractŽ¡‘:âV‘þÑALueº.‘ë=The›ît•¾9w“o˜compAÇonen“ts˜are˜bAÇoth˜maps.‘ë=TheŽ¡‘:â rst›v–compAÇonen¾9t,–ŽæëMcº,“maps˜the˜con¾9text˜on˜the˜functionŽ¡‘:âto–7;conš¾9text“on“the“argumen˜t,‘c§whilst“ëMa“ºmaps“the“abstractŽ¡‘:âv›ÿ|ralue–5ëof“the“argumen¾9t“to“the“abstract“v˜alue“of“the“re-Ž¡‘:âsult.‘É V‘ÿ:«ariables–NÝdenoting“abstract“v‘ÿ|ralues“or“abstractŽ¡‘:âv‘ÿ|ralue–Tmaps“ha•¾9v“e–T'a'“as“their“ rst“letter.ŽŸ‹‘íºâNotice–nhoš¾9w“the“t˜w˜o“kinds“of“v‘ÿ|ralues“are“m˜utually“recursiv˜e.Ž¡‘íºâThe›’Œo•¾9v“erall˜output˜of˜the˜abstract˜in“terpreter˜is˜one˜ab-Ž¡‘íºâstract–B}v›ÿ|ralue“pAÇer“Core“function.‘£ëEac¾9h“abstract“v˜alue“con-Ž¡‘íºâtains–®®enough“information“to“propagate“demand“from“theŽ¡‘íºâo•¾9v“erall–½ýresult“to“eacš¾9h“of“the“argumen˜ts,‘Ïuev˜en“in“the“presenceŽ¡‘íºâof–hÉfunctional“parameters.‘ÎThese“concepts“are“confusing,‘}¦soŽ¡‘íºâsome–>2examples“are“in“order.‘ÔºFirst,‘i9de ne“four“selectors“ëMFncAº,Ž¡‘íºâëMFncCº,–Ø„ëMFvalA›Øtºand“ëMFvalC˜ºto“disassem¾9ble“ëMFncºs“and“ëMFvalºs,‘ä­withŽ¡‘íºâthe–¯œbAÇehaš¾9viour“sho˜wn“in“T›ÿ:«able“1.‘úˆHopAÇefully˜,‘Ãôtheir“names“willŽ¡‘íºâserv¾9e–Tas“a“reminder“of“their“meaning.Ž© ‘íºâLet's– ©‰start“with“the“simplest“function“imaginable:Ž¡‘íºâëMid–¹–::“Int“->“Intº.‘ðThe– Óonly“remotely“inš¾9teresting“thing“w˜eŽ¡‘íºâcan–“îsaš¾9y“abAÇout“ëMid“ºis“that“it“simply“propagates“the“con˜text“onŽ¡‘íºâits–4£result“to“the“conš¾9text“on“its“argumen˜t.‘z]So,‘“c)Ž¡‘íºâºLet's–]ÃbAÇe“clear“what“this“is.‘õ½It's“ëRnot“ºa“con¾9text,‘oßand“it's“alsoޤ ‘íºâëRnot–Ë{ºan“abstract“v‘ÿ|ralue.‘ÒIt's“a“map“from“conš¾9texts“to“con˜texts.ަ‘íºâBut–×that's“not“go•AÇo“d–×enough.‘aúW‘ÿ:«e“said“earlier“that“AnnaŽ¡‘íºâprošAÇduces–êone“abstract“v‘ÿ|ralue“p˜er“Core“function.‘32So“what“doŽ¡‘íºâw¾9e–«(proAÇduce“for“ëMidº?‘ÝíF‘ÿ:«or“a“start,›Ðsince“ëMid“ºis“a“function,˜w¾9eŽ¡‘íºâmš¾9ust–²Wget“a“functional“abstract“v‘ÿ|ralue:‘êñan“ëMFval“ºterm.‘ûqIt“m˜ustŽ¡‘íºâloAÇok‘Tlik¾9e:Ž©‹‘ûç¤ëMid–¹–=“Fval“context_mapŽ¡‘+'€abstract_value_mapަ‘íºâºNo•¾9w,‘Éthe›¶con“text˜map,‘Éas˜w“e˜just˜men“tioned,‘Émaps˜the˜con-Ž¡‘íºâtext–]ªon“ëMid“ºto“the“conš¾9text“on“ëMidº's“argumen˜t.‘ß7And“the“con˜textŽ¡‘íºâon–÷±ëMidº,›ýžsince“ëMid“ºis“a“function,˜mš¾9ust“bAÇe“a“function“con˜text,‘ýžofŽ¡‘íºâthe–øÜform“ëM(Fnc–¹–a“c)º,‘1¾where–øÜëMc“ºis“the“bit“w¾9e're“really“after.Ž¡‘íºâThis–&givš¾9es“a“con˜text“map“of“ëM(\c–¹–->“FncC“c)º,‘Úso–&w˜e'v˜e“no˜wŽ¡‘íºâgot:ަ‘ûç¤ëMid–¹–=“Fval“(\c“->“FncC“c)Ž¡‘+'€abstract_value_mapŽŽŽ þ¦d’õºâºWhat–¸ñof“the“abstract“v‘ÿ|ralue“map?‘HIt“tells“us“what“the“ab-ޤ ’õºâstract–Yv›ÿ|ralue“of“ëMidº's“result“is“giv¾9en“the“abstract“v˜alue“of“ëMidº'sŽ¡’õºâargumen¾9t.‘ݰBut,›;/for–ithis“instance“of“ëMidº,˜the“result“t¾9ypAÇe“isŽ¡’õºâëMIntº.‘e¦All–ƒnon-function“tš¾9ypAÇes“ha˜v˜e“a“correspAÇonding“abstractŽ¡’õºâv‘ÿ|ralue,–õŸdenoted›í²ëM#º,“in˜a˜1-pAÇoin•¾9t˜domain.‘:So˜w“e˜don't˜actuallyŽ¡’õºâcare–Þ@what“the“abstract“v‘ÿ|ralue“of“ëMid“ºis“{“it“can“only“bAÇe“ëM#“ºan¾9y-Ž¡’õºâw•¾9a“y‘ÿ:«.‘oThat–·Tmeans,‘ßÔafter“installing“the“abstract“v‘ÿ|ralue“map,Ž¡’õºâwš¾9e–YŸcould“write“either“of“the“follo˜wing,‘j²although“the“secondŽ¡’õºâis–Ta“little“clearer:Ž©ÐO’ç¤ëMid–¹–=“Fval“(\c“->“FncC“c)Ž¡’3'€(\a–¹–->“a)Ž¡¡’ç¤id–¹–=“Fval“(\c“->“FncC“c)Ž¡’3'€(\a–¹–->“#)ަ’õºâºIf–&ây¾9ou“are“confused,‘kEgo“no“further!‘QIt“is“bAÇetter“to“returnŽ¡’õºâto–t€the“start“of“this“section,‘ŒKconsider“again“the“meanings“ofŽ¡’õºâconš¾9texts–6Øand“abstract“v‘ÿ|ralues,‘?9and“iterate“un˜til“the“exampleŽ¡’õºâmak¾9es‘Tsense.ŽŸ ’õºâMoš¾9ving–Ton“to“ëM(+)–¹–::“Int“->“Int“->“Int‘Tºgiv˜es:ަ’ç¤ëM(+)–¹–=“Fval“(\c1“->“FncC“(FncC“c1))Ž¡’7á(\a1–¹–->“Fval“(\c2“->“FncC“c2)Ž¡’uM´(\a2–¹–->“#))ަ’õºâºThis–Õ¨time“currying“comes“inš¾9to“pla˜y‘ÿ:«.‘]kThat's“wh˜y“the“termŽ¡’õºâwhicš¾9h–Qƒmaps“the“abstract“v‘ÿ|ralue“of“the“ rst“argumen˜t“to“theŽ¡’õºâabstract–èv‘ÿ|ralue“of“the“result“returns“a“ëMFval“ºterm:‘Ââthe“\re-Ž¡’õºâsult"–oØhere“has“t¾9ypAÇe“ëMInt–¹–->“Intº.‘+ûClearly‘ÿ:«,‘†yëM(+)–oغsimply“prop-Ž¡’õºâagates–5conš¾9text“on“the“o˜v˜erall“result“to“bAÇoth“argumen˜ts,Ž¡’õºâwhicš¾9h–‹§is“wh˜y“the“con˜text“maps“for“the“t˜w˜o“argumen˜tsŽ¡’õºâare›%+ëM(\c1–¹–->“FncC“(FncC“c1))˜ºand˜ëM(\c2“->“FncC“c2)º.‘KõIfŽ¡’õºâthis–seems“a“little“m¾9ysterious,‘*íbšAÇear“in“mind“that“b˜othŽ¡’õºâëM(FncC–¹–(FncC“c1))–Xºand“ëM(FncC‘¹–c2)“ºrefer“to“the“con¾9text“onŽ¡’õºâthe–Of nal“result.‘ ʧThat's“bAÇecause“ëMc1“ºbinds“to“a“con¾9textŽ¡’õºâin›M¬ëMInt–¹–->“Int“->“Intº,‘ÛÁwhic¾9h˜is˜necessarily˜of˜the˜formŽ¡’õºâëM(Fnc–¹–#“(Fnc“#“cc))–ܺwhere“ëMcc“ºis“the“con¾9text“on“the“ nalŽ¡’õºâresult.‘òeSimilarly‘ÿ:«,‘°nëMc2–—4ºis“a“conš¾9text“of“t˜ypAÇe“ëMInt–¹–->“Intº,‘°nha˜vingŽ¡’õºâthe–~;form“ëM(Fnc–¹–#“cc)–~;ºwhere“ëMcc“ºis“again“the“con¾9text“on“theŽ¡’õºâ nal‘Tresult.ŽŸ ’õºâNoš¾9w–Û?for“something“altogether“more“adv˜en˜turous:‘ÿfthe“famil-Ž¡’õºâiar–ªxëMapply“ºfunction,‘ÏÁat“t¾9ypAÇe“ëM(Int–¹–->“Int)“->“Int“->“Intº.Ž¡’õºâThis–ÔÈexample“is“easier“to“follo¾9w“if“one“bAÇears“in“mind“thatŽ¡’õºâëM(apply–¹–f“x)–íºreduces“immediately“to“ëM(f‘¹–x)º,‘“so“anš¾9y“con˜textŽ¡’õºâapplied–öÖto“the“former“expression“also“applies“directly“to“theŽ¡’õºâlatter.‘ZWhat–á¢the“rather“formidable“term“bšAÇelo¾9w“do˜es“is“toŽ¡’õºâroute–[†the“con¾9text“from“the“result“of“calling“ëMapply“ºto“theŽ¡’õºâresult–Tof“calling“the“higher-order“parameter.ŽŽŽŽŽŽŸ’çjã8ŽŽŒ‹ Ör •ºâ ý? £ ý€‘ûç¤ëMapply–¹–=“Fval“(\c1“->“Fnc“(FncA“(FncC“c1))ޤ ‘rJ(FncC–¹–(FncC“c1)))Ž¡‘9TB(\a1–¹–->“Fval“(\c2“->“(FvalC“a1)Ž¡’œ(Fnc–¹–(FncA“c2)Ž¡’´-~(FncC‘¹–c2))Ž¡‘vÀà(\a2–¹–->“(FvalA“a1)“a2))ŽŸj‘íºâºFirst–Hfof“all,‘Õ*consider“what“the“function“con¾9text“ëMc1“ºwillŽ¡‘íºâget–3bšAÇound“to“m¾9ust“lo˜ok“lik¾9e:‘-ëM(Fnc›¹–a_ho“(Fnc˜#˜c_final))Ž¡‘íºâºwhere–‚¹ëMa_ho“ºus“the“abstract“(or“forw¾9ard)“v‘ÿ|ralue“of“the“func-Ž¡‘íºâtional–º˜parameter“and“ëMc_final“ºis“the“con¾9text“on“the“resultŽ¡‘íºâof–Èapplying“this“functional“parameter“to“something.‘4ÏNo¾9w,Ž¡‘íºâterm‘NëM(\c1–¹–->“Fnc“(FncA“(FncC“c1))“(FncC“(FncC“c1)))Ž¡‘íºâºmaps–ì;conš¾9text“on“ëMapply“ºto“con˜text“on“the“ rst“parameter.Ž¡‘íºâAs–˜ythis“is“a“functional“parameter,‘¹Bit“mak¾9es“sense“that“thisŽ¡‘íºâexpression–4 is“built“from“a“ëMFncº.‘ÑXSo“just“what“con¾9text“is“propa-Ž¡‘íºâgated–Ðnto“the“functional“parameter?‘yW‘ÿ:«ell,‘Þ6the“abstract“v‘ÿ|ralueŽ¡‘íºâm¾9ust–åîbAÇe“the“same“as“the“abstract“v‘ÿ|ralue“of“the“second“pa-Ž¡‘íºârameter–¬½to“ëMapplyº,‘Ò—and“this“v‘ÿ|ralue“(whicš¾9h“m˜ust“bAÇe“ëM#º)“is“ex-Ž¡‘íºâtracted–´qb¾9y“the“term“ëM(FncA–¹–(FncC“c1))–´qºSimilarly‘ÿ:«,‘Ü8the“con-Ž¡‘íºâtext–sson“the“result“of“the“functional“parameter“m¾9ust“bAÇe“theŽ¡‘íºâsame–øsas“the“conš¾9text“on“the“o˜v˜erall“result“of“ëMapplyº,‘þ9giv˜en“b˜yŽ¡‘íºâëM(FncC–¹–(FncC“c1))º.Ž© ‘íºâEvš¾9erything–”else“is“easier“to“follo˜w.‘Ç…V‘ÿ:«ariable“ëMa1“ºwill“get“bAÇoundŽ¡‘íºâto– cthe“abstract“v‘ÿ|ralue“of“the“functional“parameter,‘'whic¾9hŽ¡‘íºâm¾9ust–"bAÇe“a“ëMFval“ºterm.‘ So“ëM(FvalC‘¹–a1)“ºreturns“the“map“usedŽ¡‘íºâbš¾9y–Çdthe“functional“parameter“to“translate“con˜text“on“itself“toŽ¡‘íºâconš¾9text–½on“its“ rst“argumen˜t.‘¬The“map“is“applied“to“theŽ¡‘íºâsame–ÜYfunction“conš¾9text“as“w˜as“built“in“the“preceding“para-Ž¡‘íºâgraph,‘;„except–3áthat“references“to“ëM(FncC‘¹–c1)“ºare“replaced“b¾9yŽ¡‘íºâëMc2º,–Twhic¾9h“is“the“same“thing.ަ‘íºâFinally‘ÿ:«,‘ëÆthe–Àâabstract“v‘ÿ|ralue“of“the“result“is“givš¾9en“b˜y“apply-Ž¡‘íºâing–æJthe“abstract“v‘ÿ|ralue“map“of“the“functional“parameter,Ž¡‘íºâëM(FvalA‘¹–a1)º,‘–to–¦the“abstract“v‘ÿ|ralue“of“the“second“parameter,Ž¡‘íºâëMa2º.ަ‘íºâTw•¾9o›Aimpro“v“emen“ts˜are˜pAÇossible.‘ŸÎFirstly‘ÿ:«,‘Lthe˜abstract˜v‘ÿ|ralueŽ¡‘íºâof–+the“result“mš¾9ust“simply“bAÇe“ëM#º,‘0~since“the“result“t˜ypAÇe“is“ëMIntº.Ž¡‘íºâSecondly‘ÿ:«,‘examination–C~of“the“de nition“of“ëMFncA‘C0ºand“ëMFncCŽ¡‘íºâºshoš¾9ws–u'that“ëM(Fnc–¹–(FncA“c)“(FncC“c))–u'ºis“equiv‘ÿ|ralen˜t“simplyŽ¡‘íºâto–TëMcº.‘pThe“impro•¾9v“ed›Tv“ersion˜is:Ž©j‘ûç¤ëMapply–¹–=“Fval“(\c1“->“FncC“c1)Ž¡‘9TB(\a1–¹–->“Fval“(\c2“->“(FvalC“a1)“c2)Ž¡‘vÀà(\a2–¹–->“#))ަ‘íºâºThe–ƒmec¾9hanism“for“dealing“with“functions“and“applicationsŽ¡‘íºâis–jLthe“hardest“part“of“the“abstract“in¾9terpreter“to“understand.Ž¡‘íºâA‘1õlittle–2/time“spAÇen¾9t“making“sense“of“this“last“example“is“a“wiseŽ¡‘íºâin•¾9v“estmen“t.ŽŸ ‘íºâWhš¾9y–Gšis“it“necessary“to“propagate“demand“in˜to“functionalŽ¡‘íºâparameters?‘pW‘ÿ:«ell,‘Tconsider:ަ‘ûç¤ëMadd1–¹–x“=“apply“(+“x)“1ަ‘íºâºIf–ë5demand“isn't“propagated“in¾9to“ëMapplyº's“functional“parame-Ž¡‘íºâter,‘$there– Xwill“bAÇe“no“demand“on“term“ëM(+‘¹–x)“ºand“none“on“ëMxº,Ž¡‘íºâgiving–[the“impression“that“ëMadd1“ºis“not“strict,‘ when“really“itŽ¡‘íºâis.ŽŸ e‘íºâ¹3.3Ž‘G·Mo¹™re–LÎabFfout“abstract“valuesŽŸm‘íºâºAll–:onon-function“expressions“yield“an“abstract“v‘ÿ|ralue“in“a“unitŽ¡‘íºâdomain.‘Ï3Ho•¾9w“ev“er,–Ê{v‘ÿ|ralue›¦@ëM#º,“used˜in˜the˜examples˜abAÇo•¾9v“e,‘Ê{isŽŽŽ ý€’õºâtoAÇo–Ë indiscriminating.‘=—The“Hask¾9ell“declaration“for“abstractޤ ’õºâv‘ÿ|ralues–TloAÇoks“(almost)“lik¾9e“this:Ž©ÐO’ç¤ëMdata‘¹–AbsValŽ¡’f=‘¹–ANonRec‘ s,[AbsVal]Ž¡’f|‘¹–ARec‘Ÿî[AbsVal]Ž¡’f|–¹–Fval‘ŸîContext“AbsValŽ¡¡’f|‘¹–AbsVar‘,ÂIdŽ¡’f|–¹–AbsLam‘,ÂId“AbsValŽ¡’f|–¹–AbsAp‘æXAbsVal“AbsValŽ¡¡’f|‘¹–FncA‘ŸîContextŽ¡’f|‘¹–FvalA‘æXAbsValŽ¡’f|–¹–SelA‘ŸîInt“AbsValŽ¡’f|‘¹–AMeet‘æX[AbsVal]ަ’õºâºThe–¢ëMARec“ºand“ëMANonRec“ºterms“de ne“abstract“v‘ÿ|raluesŽ¡’õºâfor–ø3recursivš¾9e“and“non-recursiv˜e“t˜yp•AÇes,‘°êresp“ectiv˜ely‘ÿ:«.‘ Å InŽ¡’õºâbšAÇoth–¬cases,‘¾the“asso˜ciated“list“of“ëMAbsValºs“are“the“ab-Ž¡’õºâstract–v‘ÿ|ralues“of“the“parameters“of“the“t¾9ypAÇe.‘ èF‘ÿ:«or“ex-Ž¡’õºâample,‘|þa–Üterm“of“t¾9ypAÇe“ëM[(Int,‘¹–Int)]“ºhas“abstract“v‘ÿ|ralueŽ¡’õºâëM(Rec–¹–[NonRec“[NonRec“[],“NonRec“[]]])º,‘†½giv¾9en–pthat“ëMIntŽ¡’õºâºis–NFtreated“as“an“enš¾9umeration“and“th˜us“maps“to“ëM(NonRec‘¹–[])º.Ž¡’õºâIt– Ôis“impAÇortanš¾9t“to“realise“that“this“v‘ÿ|ralue“is“still“unitary‘ÿ:«,‘Tlik˜eŽ¡’õºâëM#º,‘”Êbut–Hhas“the“added“adv‘ÿ|ran¾9tage“that“it“can“bAÇe“disassem-Ž¡’õºâbled–“~to“revš¾9eal“its“unitary“sub•AÇcomp“onen˜ts,‘­vas–“~necessitated“b˜yŽ¡’õºâthe–µƒabstract“inš¾9terpretation“of“ëMcase“ºstatemen˜ts.‘ü€ConstructorŽ¡’õºâëMSelA–Tºis“used“for“this,“with“meaning:Ž©ÐO’ç¤ëMSelA–¹–n“(ARec‘æX[a1“...“an“...“ak])‘ s,=“anŽ¡’ç¤SelA–¹–n“(ANonRec“[a1“...“an“...“ak])‘ s,=“anަ’õºâFvalº,‘pµëMFncA–^[ºand›^nëMFvalA“ºw•¾9ere˜in“troAÇduced˜in˜the˜previous˜sec-Ž¡’õºâtion.‘ÎÒëMAbsVarº,‘[ ëMAbsLam–,{ºand“ëMAbsAp“ºallo¾9w“references“to“abstract-Ž¡’õºâv–ÿ|ralued›°qv“ariables,‘8and˜for˜the˜creation˜and˜application˜ofŽ¡’õºâabstract-v‘ÿ|ralued–g9mappings.‘ Observš¾9e“that“w˜e“often“omitŽ¡’õºâëMAbsVar–îRºand“ëMAbsApº,›$’when“the“meaning“is“ob¾9vious,˜and“ab-Ž¡’õºâbreviate›TëM(AbsLam–¹–a“e)˜ºto˜ëM(\a“->“e)º.ŽŸ ’õºâConsider‘TagainޤÐO’ç¤ëM1–¹–+“(head“xs“(y+1))Ž¡’õºâºwhere›tÕëMxs–¹–::“[Int“->“Int]º.‘:ôW‘ÿ:«e˜expAÇect˜ëMxs˜ºto˜ha•¾9v“e˜bAÇeenޤ ’õºâbAÇound–Ô*to“an“abstract“v‘ÿ|ralue“whic¾9h“can“supply“a“sensibleŽ¡’õºâconš¾9text-mapping–:$function.‘ŠàOnce“again,‘CXw˜e“c˜haracterise“theŽ¡’õºâlist–F0bš¾9y“the“least“elemen˜t,‘ožthis“time“the“least“con˜text“function,Ž¡’õºâin–Tit.‘pSo,“suppAÇosingޤÐO’ç¤ëMxs–¹–=“[id,“id]“where“id“x“=“xŽ¡’õºâºthe–Tabstract“v‘ÿ|ralue“of“ëMxs“ºwill“bAÇe:Ž¡’ç¤ëMARec–¹–[‘ s,Fval“(\c1“->“FncC“c1)Ž© ’ATB(\a1–¹–->“ANonRec“[])‘ s,]Ž¡’õºâºThe–ìÅe ect“of“the“ëMhead“ºfunction“is“to“wrap“ëMSelA‘¹–1“ºaroundަ’õºâthis–ƒöterm,‘ŸŸmaking“the“abstract“v›ÿ|ralue“of“ëMid“ºa¾9v˜ailable“whereަ’õºâit–Tis“needed.‘pBut,“noš¾9w,“if“ëMxs“ºw˜ere“de ned“asŽ¡’ç¤ëMxs–¹–=“[id,“const]“where“id“x‘Ÿî=“xަ’p”const–¹–x‘ s,=“42ŽŽŽŽŽŸ’çjãº9ŽŽŒ‹ óÆ •ºâ ý? £ ý€‘íºâºwš¾9e–²need“to“bAÇe“more“cautious.‘òµSince“the“abstract“in˜terpre-ޤ ‘íºâtation–ybcannot“distinguish“items“in“lists,‘Òewš¾9e“m˜ust“arrangeŽ¡‘íºâthat–´öthe“function“whicš¾9h“emerges“from“the“list“represen˜ts“theŽ¡‘íºâw•¾9eak“er–b˜ev‘ÿ|raluator:‘¶ùëMconstº.‘=That“requires“the“list“as“a“wholeŽ¡‘íºâto›Tha•¾9v“e˜v‘ÿ|ralue:Ž©Zû‘ûç¤ëMARec–¹–[‘ s,Fval“(\c1“->“_)Ž¡‘9TB(\a1–¹–->“ANonRec“[])‘ s,]ަ‘íºâºThe–2upshot“of“all“this“is“that“the“abstract“v‘ÿ|ralue“of“a“listŽ¡‘íºâconš¾9taining–©functions“is“c˜haracterised“b˜y“the“least“functionŽ¡‘íºâin–ʾthe“list,‘øwith“the“principle“extending“analogously“to“allŽ¡‘íºâother–„8structures.‘iIn“order“to“carry“that“out,‘ßða“greatest-Ž¡‘íºâlo•¾9w“er-b•AÇound›¯‘op“eration˜is˜needed˜for˜abstract˜v‘ÿ|ralues.‘ú„This˜isŽ¡‘íºâwhat–Tthe“ëMAMeet“ºterm“is“for.ŽŸìÑíºâ¹3.4Ž‘G·Mo¹™re–LÎabFfout“contextsŽŸm‘íºâºThis–æ.is“a“go•AÇo“d›æ.p“oin•¾9t˜at˜whic“h˜to˜wheel˜in˜the˜Hask“ell˜decla-Ž¡‘íºâration–0&for“conš¾9texts.‘læUnfortunately‘ÿ:«,‘6Ûit“is“ev˜en“more“cum˜bAÇer-Ž¡‘íºâsome–Tthan“the“ëMAbsVal“ºdeclaration.‘pNev¾9ertheless:ަ‘ûç¤ëMdata‘¹–ContextŽ¡‘ f=‘¹–Stop1Ž¡‘ f|‘¹–Up1‘Y„[Context]Ž¡‘ f|‘¹–Stop2Ž¡‘ f|‘¹–Up2Ž¡‘ f|‘¹–UpUp2‘æX[Context]Ž¡‘ f|–¹–Fnc‘Y„AbsVal“ContextŽ¡¡‘ f|‘¹–FncC‘ŸîContextŽ¡‘ f|‘¹–FvalC‘æXAbsValŽ¡¡‘ f|‘¹–CJoin‘æX[Context]Ž¡‘ f|‘¹–CMeet‘æX[Context]Ž¡¡‘ f|‘¹–CtxVar‘,ÂIdŽ¡‘ f|–¹–CtxLam‘,ÂId“ContextŽ¡‘ f|–¹–CtxAp‘æXContext“ContextŽ¡¡‘ f|–¹–SelU‘ŸîInt“ContextŽ¡‘ f|–¹–SelUU‘æXInt“ContextŽ¡‘ f|–¹–CaseU‘æXContext“Context“ContextŽ¡‘ f|–¹–CaseUU‘,ÂContext“Context“Context“ContextŽ¡¡‘ f|‘¹–DefU‘ŸîContextŽ¡‘ f|‘¹–DefUU‘æXContextަ‘íºâºThe–S rst“six“are“for“building“literal“con¾9texts.‘Õ«ëMStop1“ºandŽ¡‘íºâëMUp1–yOºpšAÇertain“to“p˜oin¾9ts“in“ëMLift–¹–(D1“x“...“x“Dn)º,‘˜„with‘yOëMStop1Ž¡‘íºâºrepresen¾9ting–§the“bšAÇottom“p˜oin¾9t“ëM_º,‘Y|and“ëM(Up1–¹–[x1“...“xn])Ž¡‘íºâºrepresenš¾9ting–the“pAÇoin˜t“ëMU[x1–¹–...“xn]º.‘Similarly‘ÿ:«,–TëMStop2º,“ëMUp2Ž¡‘íºâºand›$uëM(UpUp2–¹–[x1“...“xn])˜ºrepresen•¾9t˜the˜pAÇoin“ts˜ëM_º,‘h=ëMU_˜ºandŽ¡‘íºâëMUU[x1–¹–...“xn]–&ºin“the“domain“ëMLift2–¹–(D1“x“...“x“Dn)º.‘ɶëMFncŽ¡‘íºâºis–Šeused“for“building“function-v‘ÿ|ralued“con¾9texts,‘¦/as“discussed“inŽ¡‘íºâsection–Hj3.2.‘µ³Finally‘ÿ:«,‘U0ëMDefU›H]ºand“ëMDefUU˜ºexist“to“help“the“termŽ¡‘íºârewriting–Tsystem,“as“describAÇed“in“section“4.4.Ž© ‘íºâëMFncC–(åºand›)!ëMFvalC“ºw¾9ere˜also˜discussed˜in˜section˜3.2.‘Í´ëMCJoin˜ºandŽ¡‘íºâëMCMeet–]=ºunsurprisingly“denote“the“least“uppAÇer“and“greatestŽ¡‘íºâlo•¾9w“er–TbšAÇounds“of“their“resp˜ectivš¾9e“argumen˜t“lists.ަ‘íºâëMCtxVarº,‘ÙæëMCtxLam–L0ºand“ëMCtxAp“ºare“exact“equiv‘ÿ|ralen¾9ts“to“theŽ¡‘íºâëMAbsVarº,‘"åëMAbsLam–ìûºand“ëMAbsAp“ºdiscussed“in“section“3.3.‘£fTheyŽ¡‘íºâproš¾9vide–ÿ¤a“w˜a˜y“to“reference“con˜text-v›ÿ|ralued“v˜ariables,‘úand“al-Ž¡‘íºâloš¾9w–8the“creation“and“application“of“con˜text-v‘ÿ|ralued“maps.ŽŽŽ ý€’õºâOnce–¡šagain,‘«note“that“w¾9e“often“omit“ëMCtxVar“ºand“ëMCtxApº,ޤ ’õºâwhen–³the“meaning“is“ob¾9vious,‘ƺand“abbreviate“ëM(CtxLam–¹–c“e)Ž¡’õºâºto‘TëM(\c–¹–->“e)º.ŽŸ ’õºâF‘ÿ:«ar–ù%and“a•¾9w“a“y–ù%the“most“in¾9teresting“constructs“are“the“lastŽ¡’õºâfour.‘¢yëMCaseU–Aöºand›BëMCaseUU“ºallo•¾9w˜partial˜disassem“bly˜of˜v‘ÿ|raluesŽ¡’õºâin›6mëMLift–¹–(D1“x“...“x“Dn)˜ºand˜ëMLift2“(D1“x“...“x“Dn)˜ºre-Ž¡’õºâspAÇectiv¾9ely‘ÿ:«,‘…fin–;Éthe“manner“discussed“in“section“2.2.3.‘ÎTheŽ¡’õºâexact–Tseman¾9tics“are:Ž©´º’ç¤ëMCaseU–¹–Stop1‘,Âx“y‘ s,=“xŽ¡’ç¤CaseU–¹–(Up1“_)“x“y‘ s,=“yŽ¡¡’ç¤CaseUU–¹–Stop2‘Ÿîx“y“z‘ s,=“xŽ¡’ç¤CaseUU–¹–Up2‘!x“y“z‘ s,=“yŽ¡’ç¤CaseUU–¹–(UpUp2“_)“x“y“z‘ s,=“zަ’õºâºNote–üdthat“the“switc¾9h“v‘ÿ|ralues“are“restricted“to“bAÇeing“in“do-Ž¡’õºâmains›½ëMLift–¹–(D1“x“...“x“Dn)˜ºand˜ëMLift2“(D1“x“...“x“Dn)Ž¡’õºâºrespAÇectiv•¾9ely‘ÿ:«.‘Switc“h–¾…v‘ÿ|ralues“from“an¾9y“other“domain“consti-Ž¡’õºâtute–$´an“ill-formed“con¾9text.‘J‘ëMCaseU›$°ºand“ëMCaseUU˜ºterms“denoteŽ¡’õºâa–îmapping“from“their“switc¾9h“expressions“to“one“of“the“al-Ž¡’õºâternativ•¾9es.‘ò(As›one“and“only“w•¾9a“y–×>to“makš¾9e“them“w˜ell-formed“is“to“wrapŽ¡’õºâthe–rappropriate“spAÇecies“of“ëMCase“ºterm“around“them,‘‰Élea¾9vingŽ¡’õºâthe–TëMSel“ºin“the“greatest-v‘ÿ|ralue“arm:ަ’ç¤ëMCaseU‘ s,c–¹–(...whatever...)“(SelU“n“c)Ž¡¡’ç¤CaseUU–¹–c“(...whatever...)“(...whatever...)Ž¡’~Àà(SelUU–¹–n“c)ަ’õºâºIn–ŽìbšAÇoth“cases,‘­Rthe“term“ëM(Sel–¹–n“c)–Žìºma¾9y“not“app˜ear“in“an¾9yŽ¡’õºâplace–Ôømark¾9ed“\ëM...whatever...º".‘[]Note“that“the“ëMSel“ºtermŽ¡’õºâmaš¾9y–2—appAÇear“an˜ywhere“within“the“greatest-v‘ÿ|ralue“arm,‘yçandŽ¡’õºâis–“|not“restricted“to“the“top“lev¾9el,‘³as“this“example“seems“toŽ¡’õºâsuggest.ŽŸþ'’õºâ¹3.5Ž’ G·Constructo¹™r–LÎfunctions“and“case“statementsŽŸm’õºâºThe–˜source-language“trappings“of“structured“tš¾9ypAÇes“giv˜e“riseŽ¡’õºâto–Nôsome“of“the“more“inš¾9teresting“parts“of“the“abstract“in˜ter-Ž¡’õºâpreter,‘NOand›Bêw•¾9arran“t˜a˜section˜to˜themselv“es.‘¥1First,‘NOthough,Ž¡’õºâsome–Tterminology‘ÿ:«.‘pA“structured“tš¾9ypAÇe“is“de ned“lik˜e“this:ަ’ç¤ëMdata–¹–typeName“v1“...“vk“=“C1“t11“...“t1mŽ¡’uM´|‘Ÿî...Ž¡’uM´|–¹–Cn“t1n“...“tnmŽŽŽŽŽŸ’åäº10ŽŽŒ‹  › •ºâ ý? £ ý€‘íºâºThis–˜de nes“a“tš¾9ypAÇe“called“ëMtypeNameº,‘¿©param˜terised“b˜y“t˜ypAÇeޤ ‘íºâv‘ÿ|rariables–Î@ëMv1“ºto“ëMvkº,‘Üxwith“constructors“ëMC1“ºto“ëMCnº.‘¿The“t¾9ypAÇe“ex-Ž¡‘íºâpressions–÷ýëMt11“ºto“ëMtnmº,‘ýÛwhicš¾9h“form“the“argumen˜ts“to“the“con-Ž¡‘íºâstructors,‘ñ are–Åhea¾9vily“constrained“in“the“manner“discussedŽ¡‘íºâin– 1section“2.2.6:‘*they“maš¾9y“only“bAÇe“either“one“of“the“t˜ypAÇeŽ¡‘íºâv‘ÿ|rariables,›i ëMv1–¹–...“vkº,˜or–XLa“direct“recursivš¾9e“call“to“the“t˜ypAÇe:Ž¡‘íºâëM(typeName–¹–v1“...“vk)º.ŽŸ ‘íºâBecause–€ of“this“constrain•¾9t,‘š¹eac“h–€ constructor“argumen¾9t“in“aŽ¡‘íºâv‘ÿ|ralid–&ìde nition“can“bAÇe“classi ed“either“as“a“recursiv¾9e“call“ëMRecº,Ž¡‘íºâor–Yas“one“of“the“tš¾9ypAÇe“v‘ÿ|rariables,‘jžëMVar‘¹–n“ºwhere“ëMn“ºis“a“n˜um˜bAÇerŽ¡‘íºâdenoting–Twhic¾9h“v‘ÿ|rariable.‘pF‘ÿ:«or“example,“the“de nitionŽ©ÐO‘ûç¤ëMdata–¹–AVLTree“i“a“bŽ¡‘ f=‘¹–ALeafŽ¡‘ f|–¹–ANode“i“(AVLTree“i“a“b)“a“b“(AVLTree“i“a“b)ަ‘íºâºcan,–Tin“principle,“bAÇe“rewritten“asަ‘ûç¤ëMdata–¹–AVLTree“(of“3“type“variables)Ž¡‘ f=‘¹–ALeafŽ¡‘ f|–¹–ANode“(Var“1)“Rec“(Var“2)“(Var“3)“Recަ‘íºâºW‘ÿ:«e–) noš¾9w“de ne“t˜w˜o“strange“functions,‘-øëMargkind“ºand“ëMupdateº,Ž¡‘íºâto–ÓŽassist“in“the“discussion“bAÇeloš¾9w.‘ WNeither“are“mean˜t“toŽ¡‘íºâbAÇe–¿ implemenš¾9table.‘”Rather,‘éxthey“serv˜e“as“con˜v˜enien˜t“nota-Ž¡‘íºâtional–êRdevices,‘‘and“are“bAÇest“illustrated“b¾9y“example.‘›jTheyŽ¡‘íºâare–§ÍbAÇoth“meaningless“unless“the“particular“constructor“ap-Ž¡‘íºâplication–Tthey“are“assoAÇciated“with“is“stated.ŽŸ ‘íºâëMargkind–…ºtells“us“what“part“of“a“data“tš¾9ypAÇe“a“giv˜en“construc-Ž¡‘íºâtor–×ìargumenš¾9t“correspAÇonds“to:‘ý¼either“a“certain“t˜ypAÇe“v‘ÿ|rariable,Ž¡‘íºâor–ý3a“recursivš¾9e“instance“of“the“t˜ypšAÇe.‘eF‘ÿ:«or“example,‘b˜earing“inŽ¡‘íºâmind–~the“declaration“abAÇo•¾9v“e,‘˜Pgiv“en–~the“constructor“applica-Ž¡‘íºâtion‘TëM(ANode–¹–i“l“a“b“r)º:ަ‘ûç¤ëMargkind–¹–i“=“Var“1Ž¡‘ûç¤argkind–¹–l“=“RecŽ¡‘ûç¤argkind–¹–a“=“Var“2Ž¡‘ûç¤argkind–¹–b“=“Var“3Ž¡‘ûç¤argkind–¹–r“=“Recަ‘íºâupdate–G ºreplaces“a“particular“v‘ÿ|ralue“in“a“supplied“list“withŽ¡‘íºâanother–Œ†v‘ÿ|ralue.‘‚It“ nds“out“whic¾9h“lošAÇcation“to“up˜date“b¾9yŽ¡‘íºâusing– wëMargkindº,‘J@expAÇecting“an“answ¾9er“of“the“form“ëM(Var‘¹–i)º,Ž¡‘íºâwhereupšAÇon–B‡ëMi“ºis“used“as“the“lo˜cation.‘¤ It“is“in¾9v‘ÿ|ralid“to“useŽ¡‘íºâëMupdate–ëºin“a“w•¾9a“y›ëwhic“h˜w“ould˜cause˜the˜call˜to˜argkindŽ¡‘íºâto–Ö_return“ëMRecº.‘ _’Again,‘F¡using“the“constructor“applicationŽ¡‘íºâëM(ANode–¹–i“l“a“b“r)º:ަ‘ûç¤ëMupdate–¹–i“"my"‘,Â["the",“"cat",“"sat"]Ž¡‘ f=–¹–["my",‘ s,"cat",“"sat"]Ž¡¡‘ûç¤update–¹–a“"dog"‘ s,["the",“"cat",“"sat"]Ž¡‘ f=–¹–["the",“"dog",“"sat"]Ž¡¡‘ûç¤update–¹–b“"ran"‘ s,["the",“"cat",“"sat"]Ž¡‘ZÐ=–¹–["the",“"cat",“"ran"]ަ‘íºâºButަ‘ûç¤ëMupdate–¹–l“x“xsŽ¡‘ûç¤update–¹–r“x“xsަ‘íºâºare–TbAÇoth“illegal“since“ëMargkind›¹–l“º=“ëMargkind˜r“º=“ëMRecº.ŽŽŽ ý€’õºâThe–$Êexample“used“ëMupdate“ºto“replace“w¾9ords“in“a“list“thereof“toޤ ’õºâemphasise–C6ëMupdateº's“pAÇolymorphic“nature.‘¦Note“that“ëMupdateŽ¡’õºâºis›Ïalw•¾9a“ys˜used˜with˜a˜constructor˜wrappAÇed˜round˜the˜ nalŽ¡’õºâlist–ö¸argumenš¾9t.‘“Dt)Ž¡’f=–¹–(\c“->“top(Ds))Ž¡¡’ç¤bot–¹–(Lift‘ s,(D1“x“...“x“Dn))Ž¡’f=‘¹–Stop1Ž¡’ç¤bot–¹–(Lift2“(D1“x“...“x“Dn))Ž¡’f=‘¹–Stop2Ž¡’ç¤bot–¹–(Ds“->“Dt)Ž¡’f=–¹–(\c“->“bot(Ds))Ž¡¡’ç¤topfv–¹–(Lift‘ s,(D1“x“...“x“Dn))Ž¡’f=–¹–ANonRec“[topfv(D1)“...“topfv(Dn)]Ž¡’ç¤topfv–¹–(Lift2“(D1“x“...“x“Dn))Ž¡’f=–¹–ARec‘æX[topfv(D1)“...“topfv(Dn)]Ž¡’ç¤topfv–¹–(Ds“->“Dt)Ž¡’f=–¹–Fval“(\c“->“top(Ds))Ž¡’3'€(\a–¹–->“topfv(Dt))ަ’õºâwhnf(D)‘ž…ºis–ž£the“w¾9eak“head“normal“form“ev‘ÿ|raluator“for“domainŽ¡’õºâëMDº.–TThis“only“mak¾9es“sense“for“certain“v‘ÿ|ralues“of“ëMDº:ަ’ç¤ëMwhnf–¹–(Lift‘ s,(D1“x“...“x“Dn))Ž¡’f=‘,ÂUp1–¹–[bot(D1)“...“bot(Dn)]Ž¡’ç¤whnf–¹–(Lift2“(D1“x“...“x“Dn))Ž¡’f=–¹–UpUp2“[bot(D1)“...“bot(Dn)]ަ’õºâºFinally‘ÿ:«,–Tfor“the“record,“a“Core“ëMcase“ºexpression“loAÇoks“lik¾9eަ’ç¤ëMcase–¹–switchExpression“ofŽ¡’fC1–¹–p11“...“p1m“->“rhs1Ž¡’3'€...Ž¡’fCn–¹–p1n“...“pnm“->“rhsnަ’õºâºwhere–X%it“is“assumed“that“all“constructors“are“presen¾9t.‘ääThisŽ¡’õºâis–Tassured“bš¾9y“the“pattern-matc˜hing“phase“of“the“desugarer.ŽŸ ’õºâThe–ífour“folloš¾9wing“sections“doAÇcumen˜t“the“ o˜w“of“abstractŽ¡’õºâv‘ÿ|ralues–^and“con¾9texts“through“constructor“applications“andŽ¡’õºâëMcase–¤'ºexpressions.‘ö¶In“some“w•¾9a“ys,‘ºÊthe›¤'t“w“o˜are˜oppAÇosites:‘ãÚcon-Ž¡’õºâstructor–kapplications“build“structures,‘O1whilst“ëMcase“ºexpres-Ž¡’õºâsions–‹Mdisassemš¾9ble“them.‘~ZAn“in˜teresting“dualit˜y“arises“fromŽ¡’õºâthis.‘ÌThe– o¾9w“of“abstract“v‘ÿ|ralues“though“case“expressionsŽ¡’õºâis– uncannily“similar“to“the“ oš¾9w“of“con˜texts“v‘ÿ|ralues“throughŽ¡’õºâconstructors,–Tand“vice“v¾9ersa.ŽŽŽŽŽŸ’åä11ŽŽŒ‹ & •ºâ ý? £ ý€‘íºâ¹3.5.1Ž‘ úíConstructoš¹™r–LÎfunctions:‘fhabstract“value“p˜ropagationŽŸm‘íºâºHoš¾9w–1do“abstract“v‘ÿ|ralues“ o˜w“through“a“constructor?‘4Theޤ ‘íºâdiscussion–§Éof“section“3.3“implied“that“the“the“ëM(:)“ºfunctionŽ¡‘íºâm•¾9ust›TbAÇeha“v“e˜something˜lik“e:ޤeh‘ûç¤ëM(:)–¹–=“\x“xs“->“AMeet“[xs,“ARec“[x]]Ž¡‘íºâºObservš¾9e–‹¦that“the“apparen˜tly“pAÇolymorphic“nature“of“this“def-ޤ ‘íºâinition–©is“incidenš¾9tal.‘ï7In“general,‘¨Ìgiv˜en“an“arit˜y-n“constructorŽ¡‘íºâëMC‘öºand–ùargumen¾9ts“ëMa1–¹–...“an–ùºwhere“ëM(C–¹–a1“...“an)“::“tauº,Ž¡‘íºâthe–Tforwš¾9ard“bAÇeha˜viour“of“C“is:Ž©eh‘ûç¤ëM\a1–¹–...“an“->“AMeet“[e1“...“en]Ž¡¡‘ûç¤ei–¹–=“aiŽ¡‘‡’if–¹–argkind“ai“=“RecŽ¡¡‘ f=–¹–ARec“(update“ai“ai“topfv(D(tau)))Ž¡‘‡’if‘,Âargkind–¹–ai“==“Var“xŽ¡‘‡’and‘ s,C–¹–is“from“a“recursive“typeŽ¡¡‘ f=–¹–ANonRec“(update“ai“ai“topfv(D(tau)))Ž¡‘‡’if‘,Âargkind–¹–ai“==“Var“xŽ¡‘‡’and‘ s,C–¹–is“from“a“non-recursive“typeަ‘íºâºNullary–„fconstructors“simply“acquire“the“top“abstract“v‘ÿ|ralueŽ¡‘íºâof–¸‡the“relev‘ÿ|ran¾9t“domain“(bAÇear“in“mind“that,‘Ëfor“a“domain“notŽ¡‘íºâcon¾9taining–“ófunction“spaces,‘³›this“is“the“same“as“the“bAÇottomŽ¡‘íºâpAÇoin¾9t).‘pThe–TëM[]“ºcase“for“ëM[Int]º,“for“example,“is:ަ‘ûç¤ëM[]–¹–=“topfv(D(“[Int]“))Ž¡‘ f=–¹–topfv(“Lift2“(Lift“())“)Ž¡‘ f=–¹–ARec“[ANonRec“[]]ަ‘íºâºThe–Ã3motiv¾9e“in“all“this“is“to“ensure“that“the“abstract“v‘ÿ|ralue“ofŽ¡‘íºâa–Žconstructor“application“is“cš¾9haracterised,‘µfor“eac˜h“parame-Ž¡‘íºâterising–Ttš¾9ypAÇe,“b˜y“the“least“v‘ÿ|ralue“of“that“t˜ypAÇe.ŽŸ ‘íºâAs–K[an“example,‘×consider“an“ob‘ƒŽjectŽ¡‘íºâof–‹þtš¾9ypAÇe“ëM(AVLTree–¹–Int“Int“Int)º.‘€oCon˜texts–‹þfor“that“t˜ypAÇeŽ¡‘íºâare–®ædra¾9wn“from“the“domain“ëMLift2–¹–(Lift“()“x“Lift“()“xŽ¡‘íºâLift‘¹–())º.‘ #ÀW‘ÿ:«e–ÄexpAÇect“the“abstract“v‘ÿ|ralue“returned“b¾9yŽ¡‘íºâbšAÇoth–þ¾the“ëMALeaf“ºand“ëMANode“ºconstructors“to“b˜e“of“the“formŽ¡‘íºâëMARec–¹–[ii,“aa,“bb]–ͺwhere“ëMii“ºrepresen¾9ts“the“least“abstractŽ¡‘íºâv‘ÿ|ralue–Qof“anš¾9y“ob‘ƒŽject“correspAÇonding“to“t˜ypAÇe“v‘ÿ|rariable“ëMi“ºin“theŽ¡‘íºât¾9ypAÇe–TAde nition,›cüand“similarly“for“ëMaa“ºand“ëMbbº.‘Ù7So,˜at“this“in-Ž¡‘íºâstanš¾9tiation,‘ Wthe–ƒabstract“v‘ÿ|ralue“bAÇeha˜viour“of“the“constructorsŽ¡‘íºâis:Ž©J®‘ûç¤ëMALeaf–¹–=“ARec“[ANonRec“[],“ANonRec“[],“ANonRec“[]]Ž¡¡‘ûç¤ANodeŽ¡‘ûç¤=–¹–\i“l“a“b“r“->Ž¡‘ZÐAMeetŽ¡‘ZÐ[–¹–ARec“[i,‘/?ÜANonRec“[],“ANonRec“[]],Ž¡‘Íül,Ž¡‘ÍüARec–¹–[ANonRec“[],“a,‘/?ÜANonRec“[]],Ž¡‘ÍüARec–¹–[ANonRec“[],“ANonRec“[],“b‘*†F],Ž¡‘ÍürŽ¡‘ZÐ]ަ‘íºâºNon-recursiv•¾9e›`~t“ypAÇes˜are˜dealt˜with˜in˜an˜exactly˜analogousŽ¡‘íºâmanner.‘ÒJF‘ÿ:«or–6âexample,‘c`the“bAÇeha¾9viour“of“the“pairing“construc-Ž¡‘íºâtor–Tat“t¾9ypAÇe“ëMInt–¹–->“Int“->“(Int,“Int)‘TºisŽŽŽ ý€’ç¤ëM(,)ޤ ’ç¤=–¹–\x“y“->Ž¡’ ZÐAMeetŽ¡’ ZÐ[–¹–ANonRec“[x,‘/?ÜANonRec“[]],Ž¡’ÍüANonRec–¹–[ANonRec“[],“y‘*†F]Ž¡’ ZÐ]Ž©q’õºâºIf–_¨yš¾9our“instincts“tell“y˜ou“this“is“m˜uc˜h“ado“abAÇout“nothing,‘ƒþy˜ouŽ¡’õºâare–;!correct.‘ØSince“all“these“examples“build“structures“with-Ž¡’õºâout–¦ïem¾9bAÇedded“function“spaces,‘½the“result“v‘ÿ|ralues“are“unitary‘ÿ:«,Ž¡’õºâand–Tma¾9y“bAÇe“written:ަ’ç¤ëM[]‘ s,=‘/?ÜARec–¹–[ANonRec“[]]Ž¡’ç¤(:)–¹–=“\x“xs“->“ARec“[ANonRec“[]]Ž¡¡’ç¤(,)–¹–=“\x“y“->“ANonRec“[ANonRec“[],“ANonRec“[]]Ž¡¡’ç¤ALeaf–¹–=“ARec“[ANonRec“[],“ANonRec“[],“ANonRec“[]]Ž¡’ç¤ANode–¹–=“\i“l“a“b“r“->Ž¡’)´TARec–¹–[ANonRec“[],“ANonRec“[],“ANonRec“[]]ŽŸ?’õºâ¹3.5.2Ž’úíConstructoš¹™r–LÎfunctions:‘fhcontext“p˜ropagationŽŸm’õºâºThe–Qname“of“the“game“here“is“to“saš¾9y“what“con˜text“propagatesŽ¡’õºâfrom–ƒMa“non-nš¾9ullary“constructor“to“its“argumen˜ts.‘fZIn˜tuitingŽ¡’õºâ rst–Ton“ëM[Int]º,“ëM(:)“ºexhibits“the“folloš¾9wing“bAÇeha˜viour:ަ’õºâëMDemand–¹–on“(x:xs)›Y„Demand“on“x˜Demand“on“xsŽ¡’õºâ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Ž¡’ÿ.UU[U[]]‘FßÊU[]‘B&4UU[U[]]Ž¡’ÿ.UU[_]‘PRö_‘K™`UU[_]Ž¡’ÿ.U_‘^¸_‘K™`_Ž¡’ÿ._‘c9N_‘K™`_ަ’õºâºA‘÷½ëMUU[U[]]–÷źconš¾9text“causes“ev‘ÿ|raluation“of“the“en˜tire“structureŽ¡’õºâof–,pthe“list,‘27and“all“the“ëMIntºs“in“it“toAÇo.‘aÅSo“wš¾9e“ma˜y“propagateŽ¡’õºâëMU[]–˜!ºto“ëMx“ºand“ëMUU[U[]]“ºto“the“tail“of“the“list.‘¤ÖThe“sameŽ¡’õºâreasoning–9œexplains“the“propagation“of“a“ëMUU[_]“ºcon•¾9text.‘Ó3No“w,Ž¡’õºâwhat–`iof“ëMU_º?‘à"This“ev›ÿ|raluator“simply“ev˜aluates“to“WHNF,“thatŽ¡’õºâis,–‹the,“ rst›ýØconstructor,“and˜giv•¾9es˜up.‘œSo˜zero˜con“text˜ma“yŽ¡’õºâbAÇe–Èýpropagated“to“either“head“or“tail.‘þSimilarly‘ÿ:«,‘ØBzero“con¾9textŽ¡’õºâpropagates–Tfrom“zero“con¾9text“on“ëM(x:xs)º.ŽŸ ’õºâIs–;Žthere“a“pattern“here?‘The“con¾9text“on“ëMxs“ºis“that“same“asŽ¡’õºâthe–ÜMconš¾9text“on“ëM(x:xs)“ºexcept“at“the“WHNF‘ÜpAÇoin˜t,‘ whilstŽ¡’õºâthe–#'con¾9text“on“ëMx“ºis“\ëMyº"“in“the“ëMUU[y]“ºcases,‘&œand“none“other-Ž¡’õºâwise.‘áÊThis–¬rlatter“opšAÇeration“could“b˜e“regarded“as“droppingŽ¡’õºâthe–rdouble-lifting,‘É*and“selecting“the“ rst“prošAÇduct“comp˜o-Ž¡’õºânenš¾9t.‘”W‘ÿ:«riting–ÍÁthe“con˜text“on“ëM(x:xs)“ºas“ëMalphaº,‘Ücon˜text“on“ëMxŽ¡’õºâºand–TëMxs“ºrespšAÇectiv¾9ely“could“b˜e“written“as:ަ’ç¤ëMDropUU–¹–1“alphaŽ¡’ç¤ZapWHNF‘¹–alphaަ’õºâºImplemen¾9ting–ºZëMDropUU›¹íºand“ëMZapWHNF˜ºdirectly“causes“ma‘ƒŽjorŽ¡’õºâproblems–Ÿ³in“the“term-rewriting“system.‘»F–ÿ:«ortunately“,‘JtheŽ¡’õºâëMCaseUU–Tºand“ëMSelUU“ºprimitiv¾9es“can“bAÇe“used“instead:ަ’útxëMDropUU–¹–n“alpha“=“CaseUU“alpha“_“_“(SelUU“n“alpha)Ž¡’útxZapWHNF–¹–alpha‘ s,=“CaseUU“alpha“_“_“alphaަ’õºâºAnalogising–Š•the“informal“argumen¾9t“leads“to“a“general“rule.Ž¡’õºâGivš¾9en–@an“arit˜y-ëMn“ºconstructor“ëMC‘?´ºand“argumen˜ts“ëMa1–¹–...“anŽ¡’õºâºwhere›S$ëM(C–¹–a1“...“an)“::“tauº,‘¢˜con¾9text˜ëMalpha˜ºon˜the˜con-Ž¡’õºâstructor–Tapplication“proAÇduces“conš¾9text“on“ëMai“ºas“follo˜ws:ŽŽŽŽŽŸ’åä12ŽŽŒ‹ =ý •ºâ ý? £ ý€‘ûç¤ëMai‘ s,=–¹–ZapWHNF“alphaޤ ‘A(if‘,Âargkind–¹–ai“==“RecŽ¡¡‘Íü=–¹–DropUU“x“alphaŽ¡‘A(if‘,Âargkind–¹–ai“==“Var“xŽ¡‘A(and‘ s,C–¹–is“from“a“recursive“typeŽ¡¡‘Íü=–¹–DropU“x“alphaŽ¡‘A(if‘,Âargkind–¹–ai“==“Var“xŽ¡‘A(and‘ s,C–¹–is“from“a“non-recursive“typeŽŸ¹'‘íºâºThe–}iëMAVLTree“ºexample“at“instance“ëM(AVLTree–¹–Int“Int“Int)Ž¡‘íºâºbAÇeha•¾9v“es–Lqas“folloš¾9ws“for“a“con˜text“ëMalpha“ºapplied“toŽ¡‘íºâëM(ANode–¹–i“l“a“b“r)º:Ž©s]‘ûç¤ëMVariable‘!DemandŽ¡‘ûç¤~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Ž¡‘ûç¤i‘B&4DropUU–¹–1“alphaŽ¡‘ûç¤l‘B&4ZapWHNF‘ s,alphaŽ¡‘ûç¤a‘B&4DropUU–¹–2“alphaŽ¡‘ûç¤b‘B&4DropUU–¹–3“alphaŽ¡‘ûç¤r‘B&4ZapWHNF‘ s,alphaަ‘íºâºConš¾9text–9%propagation“for“non-recursiv˜e“t˜ypšAÇes“b˜eha•¾9v“es–9%in“aŽ¡‘íºâsimilar–N¬manner,‘]except“that“it“is“no“longer“pAÇossible“to“gen-Ž¡‘íºâerate–)]ëMZapWHNFº,“and“the“drop-select“opAÇerator“only“drops“oneŽ¡‘íºâpAÇoinš¾9t,‘ö%instead–îYof“t˜w˜o.‘rThis“opAÇerator,‘ö%called“ëMDropUº,“is“imple-Ž¡‘íºâmen¾9ted‘Tasޤ¹'‘ûç¤ëMDropU–¹–n“alpha‘ s,=“CaseU“alpha“_“(SelU“n“alpha)Ž¡‘íºâºF‘ÿ:«or–ÿ7a“con¾9text“ëMalpha“ºapplied“to“ëM(x,–¹–y)“::“(Int,“Int)º,‘£theޤ ‘íºâcon¾9texts–ÒËpropagated“to“ëMx“ºand“ëMy“ºare“ëM(DropU–¹–1“alpha)‘Ò˺andŽ¡‘íºâëM(DropU–¹–2“alpha)‘TºrespAÇectiv¾9ely‘ÿ:«.ŽŸ ‘íºâT‘ÿ:«ranslation–gvof“ëMDropUº,“ëMDropUU›gJºand“ëMZapWHNF˜ºin¾9to“the“ëMCase“ºandŽ¡‘íºâëMSel– ݺprimitiv¾9es“requires“some“passing“around“of“domains,‘[soŽ¡‘íºâthat–¥the“appropriate“kind“of“bšAÇottom“v‘ÿ|ralues“can“b˜e“man¾9ufac-Ž¡‘íºâtured.ŽŸÿ‘íºâ¹3.5.3Ž‘ úíCase–LÎexpš¹™ressions:‘fhabstract“value“p˜ropagationŽŸm‘íºâºThe–æQtask“here“is“to“ gure“out“what“abstract“v‘ÿ|ralues“to“at-Ž¡‘íºâtacš¾9h–ôÚto“constructor“v‘ÿ|rariables“in“a“case“expression,‘ûYgiv˜en“theŽ¡‘íºâabstract–TUv‘ÿ|ralue“of“the“switc¾9h“expression.‘ÙrThe“solution“is“re-Ž¡‘íºâmark‘ÿ|rably–`äsimilar“to“propagation“of“con¾9texts“to“constructorŽ¡‘íºâargumen•¾9ts,‘^3and›O follo“ws˜a˜theme˜whic“h˜should˜b•AÇe˜b“ecomingŽ¡‘íºâfamiliar.‘pGiv¾9en–Ta“case“expressionŽ©¹'‘ûç¤ëMcase–¹–sw“ofŽ¡‘ f...Ž¡‘ fC–¹–a1“...“an“->“rhsŽ¡‘ f...ަ‘íºâºand–L¹an“abstract“v‘ÿ|ralue“assoAÇciated“with“ëMsw“ºof“ëMfswº,‘tØthe“abstractŽ¡‘íºâv‘ÿ|ralue–TassoAÇciated“with“ëMai“ºisަ‘ûç¤ëMai‘ s,=‘¹–fswŽ¡‘A(if‘,Âargkind–¹–ai“==“RecŽ¡¡‘Íü=–¹–SelA“x“fswŽ¡‘A(if‘,Âargkind–¹–ai“==“Var“xަ‘íºâºLet–wØthe“abstract“v‘ÿ|ralue“of“the“switc¾9h“expression“bAÇe“denotedŽ¡‘íºâëMfswº.‘pF‘ÿ:«or–TëM[Int]“ºwš¾9e“ha˜v˜e:ŽŽŽ ý€’ç¤ëMcase–¹–sw“ofޤ ’f[]‘Ÿî->‘ s,rhs1Ž¡’f(x:xs)‘¹–->‘ s,rhs2ޤƒ’õºâºgiving–Tbindings“ofŽ¡’ç¤ëMx– s,--->“SelA–¹–1“fswŽ© ’ç¤xs‘¹–--->‘ s,fswŽ¡’õºâ(AVLTree–¹–Int“Int“Int)‘Tºgiv¾9es:Ž¡’ç¤ëMcase–¹–sw“ofަ’fALeaf‘8³->‘¹–rhs1ަ’fANode–¹–i“l“a“b“r‘ s,->“rhs2ަ¦’ç¤i– s,--->“SelA–¹–1“fswަ’ç¤l– s,--->“fswަ’ç¤a– s,--->“SelA–¹–2“fswަ’ç¤b– s,--->“SelA–¹–3“fswަ’ç¤r– s,--->“fswŽ¡’õºâºFinally‘ÿ:«,–TëM(Int,‘¹–Int)“ºgiv¾9es:Ž¡’ç¤ëMcase–¹–sw“ofަ’f(x,–¹–y)‘ s,->“rhs1ަ¦’ç¤x– s,--->“SelA–¹–1“fswަ’ç¤y– s,--->“SelA–¹–2“fswޤô’õºâ¹3.5.4Ž’úíCase–LÎexpš¹™ressions:‘fhcontext“p˜ropagationŽŸm’õºâºThis–Ñösection“establishes“hoš¾9w“con˜text“on“a“ëMcase“ºexpressionަ’õºâpropagates–kto“conš¾9text“on“the“switc˜h“expression.‘¦First,‘Àaަ’õºâsubsidiary‘Tresult.Ž¡’õºâ¹F•¹™o“rw“a“rds›LÎp“ropagation˜of˜contexts˜though˜constructo“rsŽŸm’õºâºGiv¾9en–5%a“constructor“application“ëM(C–¹–a1“...“an)“::“tauº,‘aütheަ’õºâmethoAÇd–G˜of“section“3.5.2“can“tell“us“hoš¾9w“con˜text“on“this“ap-ަ’õºâplication–C¸maps“to“conš¾9text“on“ëMa1–¹–...“anº.‘§›Ho˜w˜ev˜er,‘OQw˜e‘C¸no˜wަ’õºâneed–Hgto“run“the“proAÇcess“in“rev•¾9erse.‘µªGiv“en–Hgsome“con¾9textsަ’õºâëMc1–¹–...“cn–Lºon“ëMa1–¹–...“anº,‘´w•¾9e›Lw“an“t˜to˜ nd˜the˜greatest˜con-ަ’õºâtext–õÈëMalpha“ºthat“ma¾9y“bAÇe“put“on“the“application,‘üconstrainedަ’õºâso–that“the“conš¾9texts“that“section“3.5.2“indicates“w˜ould“thenަ’õºâpropagate–ºto“ëMa1–¹–...“an–ººare“less“than“or“equal“ëMc1–¹–...“cnަ’õºâºrespAÇectiv¾9ely‘ÿ:«.ŽŸ ’õºâThe–ñ§folloš¾9wing“sc˜heme“is“o ered,‘øÉagain“without“justi cation.ަ’õºâIf–TëMC“ºis“from“a“recursivš¾9e“t˜ypAÇe:ޤƒ’ç¤ëMalpha–¹–=“CJoin“[Up2,“CMeet“[e1“...“en]]ަ¦’ç¤ei–¹–=“aiަ’‡’if‘,Âargkind–¹–ai“==“Recަ¦’f=–¹–update“ai“ai“top(D(tau))ަ’‡’if‘,Âargkind–¹–ai“==“Var“xŽ¡’õºâºIf–pëMC‘Pºis“from“a“non-recursivš¾9e“t˜ypšAÇe,‘¯6ëM(argkind‘¹–ai)“ºcannot“b˜eަ’õºâëMRecº,–Tso“this“simpli es“to:Ž¡’ç¤ëMalpha–¹–=“CMeet“[e1“...“en]ަ¦’ç¤ei–¹–=“update“ai“ai“top(D(tau))ަ’‡’if‘,Âargkind–¹–ai“==“Var“xŽŽŽŽŽŸ’åäº13ŽŽŒ‹U  •ºâ ý? £ ý€‘íºâºFinally‘ÿ:«,–Tfor“nš¾9ullary“constructors,“lik˜e“ëM[]º:ޤk‘ûç¤ëMalpha–¹–=“ctop(D(tau))Ž¡‘íºâºExamples:‘pgiv¾9en›TëM(a1,–¹–a2)“::“(Int,“Int)º,˜w¾9e˜getŽ¡‘ûç¤ëMalpha–¹–=“CMeet“[“Up1“[c1,‘æXU[]“],Ž© ‘GUp1–¹–[U[],‘,Âc2]“]Ž¡‘íºâ(a1:a2)–¹–::“[Int]‘Tºgiv¾9esŽ¡‘ûç¤ëMalpha–¹–=“CJoin“[“Up2,ަ‘GCMeet–¹–[“UpUp2“[c1],ަ‘mM´c2‘¹–]ަ‘> Ø]Ž¡‘íºâ[]–¹–::“[Int]‘Tºgiv¾9esŽ¡‘ûç¤ëMalpha–¹–=“UpUp2“[Up1“[]]Ž¡‘íºâ(ANode–¹–a1“a2“a3“a4“a5)“::“(ATree“Int“Int“Int)‘Tºgiv¾9esŽ¡‘ûç¤ëMalpha–¹–=“CJoinަ‘!´T[‘¹–Up2,ަ‘+'€CMeet–¹–[“UpUp2“[c1,‘æXU[],‘,ÂU[]“],ަ‘Pô0c2,ަ‘Pô0UpUp2–¹–[U[],‘,Âc3,‘æXU[]“],ަ‘Pô0UpUp2‘¹–[U[],–,ÂU[],“c4‘ s,],ަ‘Pô0c5‘¹–]ަ‘!´T]ŽŸë‘íºâ¹Using–LÎthe“lemmaŽŸm‘íºâºAnd–»inoš¾9w“to“return“to“the“main“theme.‘¯A˜t“this“pAÇoin˜t,‘äîit'sަ‘íºânecessary–{¸to“inš¾9troAÇduce“a“function“w˜e“will“see“a“lot“more“ofަ‘íºâlater.‘ßThe–¾yfunction“ëMC‘¾Mºtells“us“hoš¾9w“m˜uc˜h“con˜text“is“propa-ަ‘íºâgated–s]to“a“v‘ÿ|rariable“ëMx“ºwhen“con¾9text“ëMalpha“ºis“propagated“toަ‘íºâsome–>Óarbitrary“expression“ëMeº.‘˜îOf“course,‘I3if“ëMx“ºdošAÇes“not“o˜ccurަ‘íºâfree–Tin“ëMeº,“the“answ¾9er“is“none.‘pW‘ÿ:«e“write“this“asŽ¡‘ûç¤ëMC–¹–x“[e]“rho“alphaŽ¡‘íºâºwith–¿Žthe“ëMe“ºin“square“brac•¾9k“ets–¿Žto“emphasise“that“ëMC‘¿bºregardsަ‘íºâit–m¦as“a“synš¾9tactic“ob‘ƒŽject.‘%fAs“bAÇecomes“apparen˜t“later,‘ƒ»ëMC‘mºalsoަ‘íºârequires–„an“en•¾9vironmen“t–„ëMrho“ºwhic¾9h“supplies“abstract“v‘ÿ|raluesަ‘íºâfor–Tall“free“v‘ÿ|rariables“in“ëMeº.ŽŸ ‘íºâRecall–Tthat“a“ëMcase“ºexpression“loAÇoks“lik¾9e“this:Ž¡‘ûç¤ëMcase–¹–sw“ofަ‘ fC1–¹–p11“...“p1m“->“rhs1ަ‘ f...ަ‘ fCn–¹–p1n“...“pnm“->“rhsnŽ¡‘íºâºNo•¾9w,‘S•giv“en›ïcon“text˜ëMalpha˜ºo“v“erall,‘S•what˜is˜the˜con“text˜onަ‘íºâëMswº?‘`aThe–Ö¤ rst“step“is“to“ nd“the“con¾9text“on“ëMp11–¹–...“pnmº.ަ‘íºâThese–Tconš¾9text“are“giv˜en“b˜y:Ž¡‘ûç¤ëM(C–¹–p11“[rhs1]“rho1“alpha)‘,Â...ަ‘ûç¤(C–¹–p1m“[rhs1]“rho1“alpha)ަ¦‘ûç¤...ަ¦‘ûç¤(C–¹–p1n“[rhsn]“rhon“alpha)‘,Â...ަ‘ûç¤(C–¹–pnm“[rhsn]“rhon“alpha)ŽŽŽ ý€’õºâºF‘ÿ:«or–D=eacš¾9h“particular“constructor,‘Oöthe“original“en˜viron-ޤ ’õºâmenš¾9t–ÑõëMrho“ºis“augmen˜ted“with“abstract“v‘ÿ|ralue“bindings“forŽ¡’õºâthe–0v‘ÿ|rariables“assoAÇciated“with“that“constructor,‘vÌgeneratingŽ¡’õºâëMrho1–¹–...“rhonº.‘ˆThese–ëœv‘ÿ|ralues“are“deriv¾9ed“from“the“abstractŽ¡’õºâv‘ÿ|ralue–å„of“the“switc¾9h“expression,‘ïas“describAÇed“in“section“3.5.3.Ž© ’õºâThe–ôHnext“step“is“to“ gure“out“what“con¾9text“can“bAÇe“safelyŽ¡’õºâapplied–wËto“eacš¾9h“constructor,‘hkno˜wing“the“con˜texts“on“theirŽ¡’õºâindividual–.4argumen¾9ts.‘gThe“methošAÇd“describ˜ed“in“the“lemmaŽ¡’õºâis–}Ùapplied,›×úonce“for“eac¾9h“constructor,˜to“the“con¾9texts“forŽ¡’õºâëMp11–¹–...“pnm–®ºjust“computed,‘TJgiving“ëMalpha1–¹–...“alphanº.Ž¡’õºâThese–‘¹–idަ’)´T(x:xs)‘ s,->‘¹–idŽ¡’õºâºThis–míëMcase“ºexpression“returns“a“function,‘„whic¾9h“is“pAÇerfectlyަ’õºâlegitimate.‘ý:But–µ—the“o•¾9v“erall›µ—con“text˜on˜it,–ݨëMalphaº,“will˜bAÇe˜aަ’õºâfunction– Êcon¾9text,‘Igand“it“is“quite“meaningless“to“scrutiniseަ’õºâsuc¾9h–a“v‘ÿ|ralue“with“ëMCaseU›ºor“ëMCaseUUº.“A˜little“thoughš¾9t“rev˜ealsަ’õºâa–yDsimple“solution.‘H?The“ëMcase“ºexpression“returns“a“function,ަ’õºâwhic•¾9h‘^Cwill,›‚áev“en“tually‘ÿ:«,˜bAÇe–^Capplied“to“something.‘ßjWhat“reallyަ’õºâmatters–“Jis“the“con¾9text“on“the“ nal“result“of“that“application:ަ’õºâif–ínon-zero,‘MÏit“means“the“ëMcase“ºexpression“will“ev•¾9en“tually‘íha“v“eަ’õºâto–ú5bAÇe“enš¾9tered,‘ÿ¢in“order“to“generate“a“function“whic˜h“in“turnަ’õºâgenerates–‘ýsome“result“to“satisfy“the“demand.‘ð¨So,‘¬Ball“w¾9e“needަ’õºâdo,›Ùªif–²fëMalpha“ºis“a“function“con¾9text,˜is“test“the“ nal“con¾9textŽŽŽŽŽŸ’åä14ŽŽŒ‹hp •ºâ ý? £ ý€‘íºâºencapsulated–„Yin“ëMalphaº,‘¡Yrather“than“ëMalpha“ºitself.‘ìGetting“theޤ ‘íºâ nal–x\conš¾9text“out“of“an“ëMnº-arit˜y“function“con˜text“is“easily“doneŽ¡‘íºâbš¾9y–Ì…wrapping“ëMn“FncC‘ÌVºselectors“round“it.‘BSo“con˜text“on“theŽ¡‘íºâswitcš¾9h–Texpression,“in“terms“of“ëMalphaº,“no˜w“loAÇoks“lik˜e:Ž©«“‘ûç¤ëMCaseUU–¹–(FncC“(FncC“.....“(FncC“alpha)“.....))Ž¡‘ú¾_Ž¡‘ú¾(CMeet–¹–[alpha1“...“alphan])Ž¡‘ú¾(CMeet–¹–[alpha1“...“alphan])ަ‘íºâºThe›Á²n•¾9um“bAÇer˜of˜ëMFncCºs˜is˜equal˜to˜the˜arit“y˜of˜ëMalphaº,‘Òlif˜ëMalphaŽ¡‘íºâºhappšAÇens–+to“b˜e“a“function“con¾9text.‘_!ëMcase“ºexpressions“return-Ž¡‘íºâing–=åfunctions“seem“to“bšAÇe“rarities,‘hüso“usually“there“will“b˜e“zeroŽ¡‘íºâëMFncCºs.‘üThe–´ZcorrespšAÇonding“mo˜di cation“of“the“ëMCaseU‘´Aºv¾9ersionŽ¡‘íºâis–•Lobš¾9vious,‘®èand“it“only“remains“to“sa˜y“that“c˜hošAÇosing“b˜et•¾9w“eenŽ¡‘íºâthe›Ð.t•¾9w“o˜no“w˜depAÇends˜on˜the˜ nal˜con“text˜encapsulated˜inŽ¡‘íºâëMalpha–Tºwhen“ëMalpha“ºis“a“function“con¾9text.ŽŸ ‘íºâAs–élour“long“journey“through“the“forest“of“suppAÇorting“ma-Ž¡‘íºâcš¾9hinery–ò¢comes“to“a“close,‘ù’so“the“ nal“destination“dra˜ws“in˜toŽ¡‘íºâsighš¾9t:‘ˆíthe–K“de nition“of“the“abstract“in˜terpreter“propAÇer.‘¿,W‘ÿ:«eŽ¡‘íºâpause–ÀGbut“brie y“to“takš¾9e“respite“in“the“follo˜wing“example,Ž¡‘íºâthen–Temš¾9bark“upAÇon“the“ nal“straigh˜t:‘psection“3.6.ަ‘ûç¤ëMcase–¹–vs“ofŽ¡‘ f[]‘Y„->‘¹–0Ž¡‘ f(x:xs)‘ s,->‘¹–xަ‘íºâºClearly‘ÿ:«,‘ÿkëMvs–¹–::“[Int]–ùðºand“the“o•¾9v“erall›ùðt“ypAÇe˜is˜ëMIntº.‘OSo˜a˜con-Ž¡‘íºâtext–« ëMalpha“ºplaced“on“the“result“m¾9ust“bAÇe“in“domain“ëMLift‘¹–()º,Ž¡‘íºâwith–Dthe“resulting“con¾9text“on“ëMvs“ºin“ëMLift2–¹–(Lift“())º.‘¨ÁSec-Ž¡‘íºâtion–Ýï3.5.4“indicates“that“the“ëM[]“ºcase“conš¾9tributes“con˜textŽ¡‘íºâëMUpUp2–¹–[Up1“[]]º.‘ØNo¾9w,‘þNpropagating–øŒëMalpha“ºto“the“ëM(:)“ºalter-Ž¡‘íºânativš¾9e–¯Üputs“con˜text“ëMalpha“ºon“ëMx“ºand“ëMStop2“º(that“is,‘Ä'none)“onŽ¡‘íºâëMxsº.‘˜ÙComš¾9bining–”"these“t˜w˜o,›³Õagain“using“section“3.5.4,˜sho¾9wsŽ¡‘íºâthat–Tthe“conš¾9text“propagated“b˜y“this“alternativ˜e“is:ަ‘ZÐëMCJoin–¹–[Up2,“CMeet“[alpha,“Stop2]]Ž¡‘ûç¤=–¹–CJoin“[Up2,“Stop2]Ž¡‘ûç¤=‘¹–Up2ަ‘íºâºThis–Tgivš¾9es“o˜v˜erall“con˜text“on“ëMvs“ºas:ަ‘ZÐëMCaseU–¹–alpha“Stop2Ž¡‘> Ø(CMeet–¹–[UpUp2“[Up1“[]],“Up2])Ž¡¡‘ûç¤=–¹–CaseU“alpha“Stop2“Up2ަ‘íºâºThat's›þin•¾9tuitiv“ely˜correct:‘Ñwith˜no˜demand˜on˜the˜resultingŽ¡‘íºâëMIntº,‘RÐthere's–F„no“(ëMStop2º)“demand“on“the“incoming“list.‘¯ÿOth-Ž¡‘íºâerwise,‘Ûw•¾9e›è&ma“y˜ev‘ÿ|raluate˜the˜list˜to˜WHNF‘çð(ëMUp2º),‘Ûthat˜is,Ž¡‘íºâto–údthe“ rst“constructor.‘uIt“is“a“pit¾9y“these“domains“can't“tellŽ¡‘íºâus–w?abAÇout“the“head-strictness“here:‘àGgiv¾9en“non-zero“demand,Ž¡‘íºâit's–~Ýobš¾9vious“w˜e“can“not“only“ev‘ÿ|raluate“to“the“ rst“construc-Ž¡‘íºâtor,‘Êbut–û§can“also“ev‘ÿ|raluate“the“ rst“elemen¾9t“of“the“list“if“it“isŽ¡‘íºânon-empt¾9y‘ÿ:«.ŽŸ™.‘íºâ¹3.6Ž‘G·De ning–LÎthe“abstract“interp¹™reterŽŸm‘íºâºSection–J3.5.4“inš¾9troAÇduced“the“con˜text- nding“function“ëMCº.“W‘ÿ:«eŽ¡‘íºâno•¾9w›‚Ÿaugmen“t˜this˜with˜ëMZº,˜the˜abstract˜in“terpreter˜itself.‘dPëMCŽ¡‘íºâºtak•¾9es›cJan“y˜Core˜expression,‘†æa˜con“text˜on˜that˜expression,‘†æandŽ¡‘íºâa–ˆ‚v›ÿ|rariable,‘¤­and“returns“the“resulting“con¾9text“on“the“v˜ariable.Ž¡‘íºâëMZ‘ø¯ºtak•¾9es›ø·an“y˜Core˜expression,‘þpand˜returns˜the˜abstract˜v‘ÿ|ralueŽ¡‘íºâof–Ç that“expression.‘XSince“the“forwš¾9ard“and“bac˜kw˜ard“ o˜ws“ofŽ¡‘íºâinformation–ÛÔare“heaš¾9vily“in˜tert˜wined,‘ tëMC›Û¡ºand“ëMZ˜ºare“m¾9utuallyŽ¡‘íºârecursiv¾9e.‘pIn–Ta“call“to“ëMC“ºorëMZŽŽŽ ý€’ç¤C–¹–x“[e]“rho“alphaޤ ’ç¤Z‘,Â[e]‘¹–rhoŽ©¦à’õºâx–³Uºis“a“v‘ÿ|rariable,›ÚÔëMe“ºis“a“Core“expression,˜ëMalpha“ºis“a“con¾9text,Ž¡’õºâand–ëMrho“ºis“an“en•¾9vironmen“t–binding“all“free“v‘ÿ|rariables“in“ëMe“ºtoŽ¡’õºâabstract–Æâv‘ÿ|ralues.‘1As“implemen¾9ted,‘óEbAÇoth“functions“carry“anŽ¡’õºâextra–.ßparameter“used“to“help“generate“new“v‘ÿ|rariable“names.Ž¡’õºâëMC‘Rºalso–Tcarries“the“domain“of“ëMx“ºso“it“can“generate“the“appro-Ž¡’õºâpriate–‡€bAÇottom“v‘ÿ|ralue“when“needed.‘rôRecall“also“that“a“CoreŽ¡’õºâexpression–·is“a“pair,‘Ééthe“ rst“part“of“whicš¾9h“is“the“t˜ypAÇe“of“theŽ¡’õºâexpression,–Tand“the“second“the“expression“propAÇer.ŽŸ-’õºâ¹3.6.1Ž’úíDe nition–LÎof“ëMZŽŸm’õºâºThe–:»abstract“v›ÿ|ralue“of“a“literal“is“a“v˜alue“in“the“appropriateŽ¡’õºâone-pAÇoin¾9t‘Tdomain.ަ’ç¤ëMZ–¹–(tau,“ALit“n)“rho‘ s,=“ANonRec“[]ަ’õºâºV‘ÿ:«ariables›Tha•¾9v“e˜their˜v‘ÿ|ralues˜loAÇok“ed˜up.ަ’ç¤ëMZ–¹–(tau,“AVar“v)“rho‘ s,=“rho“vަ’õºâºApplications–÷are“a“little“more“tric¾9ky‘ÿ:«.‘\YFirst,‘ÚŸthe“abstractŽ¡’õºâv‘ÿ|ralue–æôof“the“function“is“created.‘‘PF‘ÿ:«rom“that,‘\the“abstract-Ž¡’õºâv‘ÿ|ralue-map–ô0is“extracted“using“ëMFvalAº,,‘úÑand“applied“to“the“ab-Ž¡’õºâstract–êv‘ÿ|ralue“of“the“argumenš¾9t“to“giv˜e“the“abstract“v‘ÿ|ralue“ofŽ¡’õºâthe‘Tresult.ަ’ç¤ëMZ–¹–(tau,“AAp“f“e)“rhoŽ¡’f=–¹–AbsAp“(FvalA“(Z“f“rho))“(Z“e“rho)ަ’õºâºLamš¾9bAÇda–üyterms“are“a“lot“more“tric˜ky‘ÿ:«.‘ÑÞLet“ëMa“ºand“ëMc“ºdenoteŽ¡’õºânew‘Tv‘ÿ|rariables.ަ’ç¤ëMZ–¹–(tau,“ALam“[x]“e)“rhoŽ¡’f=–¹–Fval“(CtxLam“c“(C“x“e“rho_c“(FncC“(CtxVar“c))))Ž¡’3'€(AbsLam–¹–a“(Z“e“rho_a))Ž¡’‡’whereŽ¡’)´Trho_c–¹–=“rho“{x“->“FncA“(CtxVar“c)}Ž¡’)´Trho_a–¹–=“rho“{x“->“AbsVar“a}ަ’õºâºAn–ëMFval“ºis“returned.‘!ŒIts“ rst“compAÇonen¾9t“is“a“map“from“theŽ¡’õºâfunction–™ªconš¾9text“ëMc“ºon“ëM(\x.e)“ºto“the“con˜text“on“parameterŽ¡’õºâëMx.–i>ºBear“in“mind“that“ëMc“ºwill“get“bAÇound“to“a“term“of“theŽ¡’õºâform›eÉëM(Fnc–¹–aa“cc)º,‘yçwhere˜ëMaa˜ºis˜the˜abstract˜v‘ÿ|ralue˜suppliedŽ¡’õºâfor– ëMx,“ºand“ëMcc“ºis“the“conš¾9text“on“ëMe.“ºSo“the“con˜text“on“ëMxŽ¡’õºâºis–š¦found“bš¾9y“ nding“ëMC‘šAºof“ëMx“ºin“ëMeº,‘ûúwith“ëMrho“ºaugmen˜ted“b˜yŽ¡’õºâbinding–ïTëMx“ºto“ëMaa,“ºthat“is,›öîto“ëMFncA–¹–(CtxVar“c)º,˜and–ïTwith“theŽ¡’õºâcon¾9text– zon“the“b•AÇo“dy– zof“the“function,– ëMeº,“equal– zto“ëMccº,‘ that“is,Ž¡’õºâëMFncC–¹–(CtxVar“c)º.Ž© ’õºâThe–ôJsecond“ëMFval“ºcompAÇonen¾9t“maps“the“abstract“v‘ÿ|ralue“ëMa“ºof“ëMxŽ¡’õºâºto–½µthe“abstract“v‘ÿ|ralue“of“ëMe.“ºThis“is“easily“done“b¾9y“computingŽ¡’õºâëMZ–Tºof“ëMeº,“with“ëMrho“ºmoAÇdi ed“to“bind“ëMx“ºto“ëMAbsVar‘¹–aº.ަ’õºâThe–TëMACase“ºcase“is“quite“easy:Ž©¦à’ç¤ëMZ–¹–(tau,“ACase“sw“[(cname1,“(pars1,“rhs1))“...Ž¡’Xô0(cnamen,–¹–(parsn,“rhsn))])Ž¡’frhoŽ¡’f=–¹–AMeet“[Z“rhs1“rho1“...“Z“rhsn“rhon]ަ’õºâºThe–xaugmenš¾9ted“en˜vironmen˜ts“ëMrhoi“(1–¹–<=“i“<=“n)–xºare“ob-Ž¡’õºâtained– Rbš¾9y“extending“ëMrho“ºto“pro˜vide“bindings“for“ëMparsi“ºinŽŽŽŽŽŸ’åä15ŽŽŒ‹ò •ºâ ý? £ ý€‘íºâºview–Œ‡of“the“v‘ÿ|ralue“of“ëMZ–¹–sw“rhoº,‘êSusing–Œ‡the“methoAÇd“of“sec-ޤ ‘íºâtion‘T3.5.3.ŽŸ ‘íºâFinally‘ÿ:«,‘¾Pthe–¨ëMAConstr“ºcase.‘ø.Although“sections“3.5.1“and“3.5.2Ž¡‘íºâcompletely–r doAÇcumenš¾9t“abstract“v‘ÿ|ralue“and“con˜text“ o˜wsŽ¡‘íºâthrough–ŽÌconstructors,‘í*wš¾9e“as“y˜et“ha˜v˜e“no“w˜a˜y“of“creatingŽ¡‘íºâabstract–bûv‘ÿ|ralues“for“constructors.‘fStarting“from“a“generalŽ¡‘íºâconstructor‘Tapplicationޤ\‘ûç¤ëMC–¹–e1“...“enŽ¡‘íºâºw¾9e–Tdesire“to“buildŽ¡‘ûç¤ëMFval–¹–(\c1“->“f1“(FncC^n“c1))ޤ ‘‡’(\a1–¹–->“Fval“(\c2“->“f2“(FncC^(n-1)“c2))Ž¡‘‡’(\a2–¹–->“...Ž¡‘9TB...Ž¡‘9TB...–¹–->“Fval“(\cn“->“fn“(FncC^1“cn))Ž¡‘rJ(\an–¹–->“aresultant)“...))Ž©\‘íºâºwhere–-ñëMFncC^i‘¹–e“ºmeans“ëMFncC‘-êºapplied“ëMi“ºtimes“to“ëMe.“ºObserv¾9eŽ¡‘íºâthat–j¢eac¾9h“use“of“ëMFncC‘jŒºhere“is“of“the“form“ëMFncC^i‘¹–cj“ºwhereŽ¡‘íºâëMi–¹–+“j“==“n“+“1º,‘»Fand–šso“all“these“terms“simply“denote“theŽ¡‘íºâcon¾9text–`on“the“result“of“the“constructor“application.‘üÇWhatŽ¡‘íºâsection–P3.5.2“proš¾9vides“is“a“w˜a˜y“to“compute“the“ëMn“ºcon˜textŽ¡‘íºâmaps,‘ý÷ëMf1–¹–...“fnº.‘±-Section–œ>3.5.1“generates“a“term“of“theŽ¡‘íºâformަ‘ûç¤ëM\a1–¹–...“\an“->“aresultantަ‘íºâºand›+ÁbAÇet•¾9w“een˜them,‘ñ\that's˜all˜that's˜needed.‘ _¸As˜thisŽ¡‘íºâis–ìÈrather“confusing,‘¢¤here's“a“couple“of“examples.‘ ¢ËF‘ÿ:«orŽ¡‘íºâëM(:)–¹–::“Int“->“[Int]“->“[Int]:ަ‘ûç¤Fval–¹–(\c1“->“DropUU“1“(FncC“(FncC“c1)))Ž¡‘‡’(\a1–¹–->“Fval“(\c2“->“ZapWHNF“(FncC“c2))Ž¡‘Pô0(\a2–¹–->“ARec“[ANonRec“[]]))ަ‘íºâºF‘ÿ:«or‘TëM(,)–¹–::“Int“->“Int“->“(Int,“Int)º:ަ‘ûç¤ëMFval–¹–(\c1“->“DropU“1“(FncC“(FncC“c1)))Ž¡‘‡’(\a1–¹–->“Fval“(\c2“->“DropU“2“(FncC“c2))Ž¡‘Pô0(\a2–¹–->“ANonRec“[ANonRec“[],Ž¡’¡G&ANonRec‘¹–[]]))ŽŸìù‘íºâ¹3.6.2Ž‘ úíDe nition–LÎof“ëMCŽŸm‘íºâºPropagation–Tof“a“conš¾9text“on˜to“a“constan˜t“has“no“e ect:ަ‘ûç¤ëMC–¹–x“(tau,“ALit“n)“rho“alphaŽ¡‘ f=–¹–bot“(domain-of-x)ަ‘íºâºThe–Tv‘ÿ|rariable“case“is:ަ‘ûç¤ëMC–¹–x“(tau,“AVar“v)“rho“alphaŽ¡‘ f=–¹–if‘æXx“==“vŽ¡‘‡’then‘ s,alphaŽ¡‘‡’else‘ s,bot‘¹–(domain-of-x)ަ‘íºâºAs–ØbšAÇefore,‘9the“application“and“lam¾9b˜da“cases“are“a“bit“mindŽ¡‘íºâbAÇending.ަ‘ûç¤ëMC–¹–x“(tau,“ALam“[y]“e)“rho“alphaŽ¡‘ f=–¹–C“x“e“rho2“(FncC“alpha)Ž¡‘‡’whereŽ¡‘!´Trho2–¹–=“rho“{y“->“FncA“alpha}ŽŽŽ ý€’õºâºHere,‘9OëMalpha–2ºis“a“function“con¾9text“bAÇeing“applied“to“ëM(\y.e).ޤ ’õºâºAssuming–@ßthat“ëMx“ºand“ëMy“ºare“not“the“same“v‘ÿ|rariable“(theŽ¡’õºâlamš¾9bAÇda-lifter–Ðassures“this),‘ÿIcon˜text“on“ëMx“ºin“ëM(\y.e)“ºcan“bAÇeŽ¡’õºâfound– Ïfrom“the“con¾9text“on“ëMx“ºin“ëMeº.‘™Since“ëMalpha“ºis“a“functionŽ¡’õºâconš¾9text,‘€¢ëMFncA‘¹–alpha–k,ºis“an“abstract“v‘ÿ|ralue“whic˜h“ëMy“ºis“bAÇoundŽ¡’õºâto,–Tgenerating“ëMrho2.“FncC‘¹–alpha“ºis“the“con¾9text“on“ëMe“ºitself.Ž©ÐO’ç¤ëMC–¹–x“(tau,“AAp“f“e)“rho“alphaŽ¡’f=–¹–CJoin“[“C“x“f“alpha_f“rho,Ž¡’ATBC–¹–x“e“alpha_e“rho“]Ž¡’‡’whereŽ¡’)´Talpha_f–¹–=“Fnc“(Z“e“rho)“alphaŽ¡’)´Talpha_e–¹–=“CtxAp“(FvalC“(Z“f“rho))“alpha_fަ’õºâºT‘ÿ:«o–·Òdeal“with“applications,‘ʆobservš¾9e“that“ëMx“ºma˜y“ošAÇccur“in“b˜othŽ¡’õºâthe–ª°function“and“argumenš¾9t“expressions,‘Ðso“w˜e“need“to“col-Ž¡’õºâlect–¿up“the“con¾9texts“from“ëMf“ºand“ëMeº,‘ÐUand“\add“them“together"Ž¡’õºâusing–©ëMCJoinº.‘ópThe“only“problem“is“ guring“out“what“con-Ž¡’õºâtext–v®propagates“to“ëMf“ºand“ëMeº.‘@~Recall“that“a“function“con-Ž¡’õºâtext–ú˜consists“of“the“abstract“v‘ÿ|ralue“of“the“argumen¾9t,‘ÿñand“theŽ¡’õºâconš¾9text–x1on“the“result.‘EHence,‘Ðèthe“con˜text“on“ëMf“ºm˜ust“bAÇeŽ¡’õºâëMFnc–¹–(Z“e“rho)“alphaº.‘ PThe–dôcon¾9text“on“ëMe“ºis“equal“to“theŽ¡’õºâconš¾9text–lythat“ëMf“ºw˜ould“propagate“to“its“argumen˜t,‘ÂBand“w˜eŽ¡’õºâknoš¾9w–Ôthat“the“con˜text“on“ëMf“ºis“ëMalpha_f.“ºSo,‘C4w˜e“build“theŽ¡’õºâabstract–í˜in¾9terpretation“for“ëMf“ºwith“ëMZ–¹–f“rhoº,‘õŠextract–í˜the“con-Ž¡’õºâtext–ìUmap“using“ëMFvalCº,“and“apply“that“to“ëMalpha_fº.‘ÆAll“told,Ž¡’õºâthat's‘TëMCtx–¹–(FvalC“(Z“f“rho))“alpha_fº.ŽŸ ’õºâDue–ëWto“the“heroic“e orts“of“section“3.5.4,‘ó½the“rather“compli-Ž¡’õºâcated–TëMcase“ºclause“is“stated“quite“succinctly:ަ’ç¤ëMC–¹–x“(tau,“ACase“sw“[(cname1,“(pars1,“rhs1))“...Ž¡’bg\(cnamen,–¹–(parsn,“rhsn))])Ž¡’Íürho‘¹–alphaŽ¡’f=–¹–CJoin“[“C“x“sw“rho“alpha_sw,Ž¡’ATBCMeet–¹–[“C“x“rhs1“rho1“alpha“...Ž¡’g òC–¹–x“rhsn“rhon“alphaŽ¡’]­Æ]Ž¡’7á]ަ’õºâºHere,‘Ý"ëMalpha_sw–µ,ºis“the“conš¾9text“on“ëMsw,“ºgiv˜en“ëMalpha“ºcon˜textŽ¡’õºâon–¦Åthe“ëMcase“ºexpression“itself,‘¼âas“computed“b¾9y“the“methoAÇd“ofŽ¡’õºâsection‘T3.5.4.Ž© ’õºâAs–¸…bAÇefore,‘Ëthe“ëMrhoi“(1–¹–<=“i“<=“n)–¸…ºare“obtained“b¾9y“extend-Ž¡’õºâing–œëMrho“ºto“pro¾9vide“bindings“for“ëMparsi“ºin“view“of“the“v‘ÿ|ralueŽ¡’õºâof›TëMZ–¹–sw“rhoº,˜using˜the˜methoAÇd˜of˜section˜3.5.3.ަ’õºâV‘ÿ:«ariable– ëMx“ºcan“appšAÇear“in“b˜oth“the“switc¾9h“expression,‘J[andŽ¡’õºâanš¾9y–&¯of“the“alternativ˜es.‘ P€T‘ÿ:«o“deal“with“the“former,‘«con-Ž¡’õºâtext–»on“ëMsw“ºis“computed“as“pAÇer“section“3.5.4,‘äand“this“con-Ž¡’õºâtext–b0propagated“inš¾9to“ëMsw.“ºCon˜text“for“ëMx“ºin“alterativ˜e“ëMi“ºisŽ¡’õºâëMC–¹–x“rhsi“rhoi“alphaº,‘Ìpbut–§Ñsince“wš¾9e“can't“sa˜y“whic˜h“alter-Ž¡’õºâativš¾9e–:Ÿwill“actually“bAÇe“selected,‘ƒñw˜e“m˜ust“tak˜e“the“greatestŽ¡’õºâlo•¾9w“er–è'bAÇound“o•¾9v“er–è'all“alternativš¾9es.‘”éFinally‘ÿ:«,‘Ûthe“switc˜h“andŽ¡’õºâalterativ•¾9e›àcon“texts˜are˜once˜again˜\added"˜using˜ëMCJoinº.‘IAsŽ¡’õºâwith–5‘the“ëMZ‘5‰ºclause“for“ëMcase“ºrho“is“extended“to“pro¾9vide“bind-Ž¡’õºâings–Tfor“the“v‘ÿ|rariables“assoAÇciated“with“eac¾9h“constructor.ަ’õºâFinally‘ÿ:«,‘Dµthe–ëMAConstr“ºcase.‘ôŒAll“the“actual“w¾9ork“of“dealingŽ¡’õºâwith–ÚÞconš¾9text“ o˜w“through“constructors“is“done“in“the“corre-Ž¡’õºâspAÇonding–?³ëMZ‘?¨ºclause.‘›All“wš¾9e“need“do“here“is“observ˜e“that“ëMx“ºisŽ¡’õºânevš¾9er–Tfree“in“an˜y“constructor,“and“so“return“zero“con˜text:ŽŸÐO’ç¤ëMC–¹–x“(tau,“AConstr“c)“rho“alphaŽ¡’f=–¹–bot“(domain-of-x)ŽŽŽŽŽŸ’åäº16ŽŽŒ‹š •ºâ ý? £ ý€‘íºâ¹4Ž‘ü”The–LÎterm“rewriting“systemŽŸ†´‘íºâ4.1Ž‘G·IntroFfductionŽŸm‘íºâºF‘ÿ:«or–*eacš¾9h“Core“function,‘o=the“abstract“in˜terpreter“proAÇducesޤ ‘íºâan–¡EëMAbsVal“ºterm.‘õÀRecursivš¾9e“groups“of“terms“require“ xpAÇoin˜t-Ž¡‘íºâing,‘-jwhicš¾9h–(™is“done“in“a“straigh˜tforw˜ard“manner.‘V>The“initialŽ¡‘íºâappro¾9ximation–vÿfor“a“function“in“domain“ëMD‘v¤ºis“ëMatop(D)º,“soŽ¡‘íºâthe–hé xpšAÇoin¾9ting“pro˜duces“the“greatest“ xp˜oin¾9t.‘/Although“itŽ¡‘íºâmighš¾9t–ôÒseem“a“little“un˜usual“to“seek“the“greatest“ xed“pAÇoin˜t,Ž¡‘íºâbAÇear–»”in“mind“that“this“approacš¾9h“represen˜ts“starting“o “fromŽ¡‘íºâa–)ôdangerous“v‘ÿ|ralue,‘YëMatop(D)‘)¸ºand“iterating“one's“w•¾9a“y–)ôto“safet¾9y‘ÿ:«.Ž¡‘íºâIn–Ôôforwš¾9ard“analyses“in“the“st˜yle“of“[Sew91Ž‘/],‘Ûdanger“is“rep-Ž¡‘íºâresen•¾9ted›I:b“y˜the˜least˜pAÇoin“t˜in˜the˜domains,‘V3and˜ xpAÇoin“tingŽ¡‘íºâyields–³/the“least“ xed“pAÇoinš¾9t.‘öIn“an˜y“case,‘Ú¦this“discussion“isŽ¡‘íºârather–W¨academic,‘h>since“w¾9e“can“claim“to“bšAÇe“lo˜oking“for“leastŽ¡‘íºâ xpšAÇoin¾9ts–¯Uhere“to˜o“simply“b¾9y“turning“all“the“domains“upside-Ž¡‘íºâdo¾9wn–pñ{“as“they“are“ nite,›‡Ùcomplete“lattices,˜sucš¾9h“a“tric˜k“isŽ¡‘íºâquite‘Tallo•¾9w“able.Ž© ‘íºâThe–‘)term“rewriter“exists“bAÇecause“of“the“need“to“compare“ap-Ž¡‘íºâproš¾9ximations–Xduring“ xpAÇoin˜ting.‘é}F‘ÿ:«or“non-recursiv˜e“terms,Ž¡‘íºâthere–ºóis,›Ístrictly“spAÇeaking,˜no“need“to“use“the“rewriter.‘þPNev-Ž¡‘íºâertheless,‘‘bAÇecause–²Rwhat“emerges“from“the“abstract“in¾9ter-Ž¡‘íºâpreter–fˆis“usually“grossly“redundan¾9t,‘ºÔall“terms“are“sub‘ƒŽjectŽ¡‘íºâto–JBrewriting,‘—}and“the“recursivš¾9e“ones“are“subsequen˜tly“ x-Ž¡‘íºâpAÇoin¾9ted.ަ‘íºâWhat–•the“rewriter“došAÇes“is“to“transform“eac¾9h“p˜ossible“termŽ¡‘íºâinš¾9to–Â}a“normal“form,‘Ósuc˜h“that“seman˜tically“equiv‘ÿ|ralen˜t“formsŽ¡‘íºâmap–9ðto“the“same“normal“form.‘ŠEDetection“of“ xed“pAÇoin¾9tsŽ¡‘íºâis–;Úthen“a“simple“matter“of“detecting“synš¾9tactic“equalit˜y“ofŽ¡‘íºâthe–normal“forms.‘%øF›ÿ:«or“higher“order“terms,‘YLunfortunately˜,Ž¡‘íºâthis–ximplies“an“abilitš¾9y“to“solv˜e“the“halting“problem.‘D‹W‘ÿ:«eŽ¡‘íºâtherefore–Vdeal“with“higher“order“functions“as“describAÇed“inŽ¡‘íºâsection–j¦5,‘ŒÉand“restrict“ourselv¾9es“to“generating“unique“normalŽ¡‘íºâforms–)Ôfor“the“abstract“in¾9terpretations“of“ rst“order“functions,Ž¡‘íºâsomething–Twhic¾9h“is,“fortunately‘ÿ:«,“decidable.ަ‘íºâThe–Ñáterm“rewriter“propšAÇer“is“an“elab˜orate“system“whic¾9h“gen-Ž¡‘íºâerates–a,normal“forms“bš¾9y“applying“man˜y“loAÇcal“transformationsŽ¡‘íºâto–v¥a“term.‘@bWhen“no“more“transformations“can“bAÇe“applied,Ž¡‘íºâthe–Mäterm“is“deemed“to“bAÇe“in“normal“form.‘Æ!Eac¾9h“kind“of“al-Ž¡‘íºâlo•¾9w“able–jÓtransformation“is“encapsulated“in“a“so-called“rewriteŽ¡‘íºârule.‘óÜEacš¾9h–]#rule“m˜ust“implemen˜t“a“seman˜tically“in˜v‘ÿ|rarian˜tŽ¡‘íºâtransformation.‘ »¸Section–õ3.2“in¾9troAÇduced“a“few“equalities,Ž¡‘íºâwhicš¾9h,–Twhen“giv˜en“a“directionalit˜y‘ÿ:«,“bAÇecome“rewrite“rules:Ž©ÐO‘ûç¤ëMFncA–¹–(Fnc“a“c)‘Ÿî===>‘,ÂaŽ¡‘ûç¤FncC–¹–(Fnc“a“c)‘Ÿî===>‘,ÂcŽ¡‘ûç¤FvalA–¹–(Fval“c“a)–,Â===>“aŽ¡‘ûç¤FvalC–¹–(Fval“c“a)–,Â===>“cަ‘íºâºMost–(×rules“are“complicated“b¾9y“the“presence“of“side-Ž¡‘íºâconditions:ަ‘ûç¤ëMFnc–¹–(FncA“c1)“(FncC“c2)–,Â===>“c1Ž¡‘ûç¤providedŽ¡‘ fc1–¹–==“c2ަ‘íºâºThese–6yexamples“illustrate“the“problem“of“whether“to“simplifyŽ¡‘íºâterms–~starting“from“the“lea•¾9v“es–~(innermost- rst)“or“from“theŽ¡‘íºâroAÇot–MÁ(outermost- rst).‘Å·Since,››Üin“the“second“example,˜theŽ¡‘íºârule–F¾only“applies“if“subterms“ëMc1“ºand“ëMc2“ºare“pro¾9v‘ÿ|rably“equal,Ž¡‘íºâinnermost- rst–Æ9rewriting“seems“necessary‘ÿ:«.‘ /But“the“sameŽ¡‘íºâstrategy–Jµapplied“to“ëMFvalC–¹–(Fval“c“a))–Jµºcould“w¾9aste“a“lotŽŽŽ ý€’õºâof–Û¯e ort“simplifying“ëMa,“ºonly“to“throš¾9w“it“a˜w˜a˜y‘ÿ:«,‘ç7so“outermost-ޤ ’õºâ rst–Tmighš¾9t“giv˜e“bšAÇetter“p˜erformance.Ž© ’õºâProš¾9viding–ÚDthe“rules“are“ nitely“con uen˜t“and“terminating,Ž¡’õºâbAÇoth–:‡approacš¾9hes“still“giv˜e“the“same“normal“forms.‘ŒObserv˜eŽ¡’õºâho•¾9w“ev“er–˜ðthat“whatevš¾9er“approac˜h“is“used,‘ù×m˜ultiple“passesŽ¡’õºâo•¾9v“er–'the“tree“will,›Zin“general,˜bAÇe“needed“to“arriv¾9e“at“nor-Ž¡’õºâmal–ÿçform.‘Ü)The“decision“can“therefore“bAÇe“based“purely“onŽ¡’õºâwhic•¾9hev“er›žœsc“heme˜giv“es˜b•AÇetter˜p“erformance.‘¸HExp“erimen¾9ta-Ž¡’õºâtion›~"sho•¾9w“ed˜that˜outermost- rst˜rewriting˜w“as˜up˜to˜tenŽ¡’õºâtimes›ZDslo•¾9w“er˜than˜innermost- rst˜for˜realistically˜sized˜termsŽ¡’õºâemitted–•?bš¾9y“the“abstract“in˜terpreter.‘œ1Although“it“w˜ould“bAÇeŽ¡’õºâfoAÇolish–Boto“claim“that“this“is“alw•¾9a“ys–Boso,‘lthe“evidence“suggestedŽ¡’õºâan–b innermost- rst“scš¾9heme“w˜ould“usually“bAÇe“m˜uc˜h“quic˜k˜er,‘…÷soŽ¡’õºâan–Tinnermost- rst“sc•¾9hemeŸü-=ó*¹Aa¨cmr6Õ1ŽŽ‘?ûºw“as‘Tadopted.ŽŸ5’õºâ¹4.2Ž’ G·P•¹™erfo“rming–LÎa“single“simpli cation“passŽŸm’õºâºBecause–¿¾the“ëMAbsVal“ºand“ëMContext“ºtš¾9ypAÇes“are“m˜utually“re-Ž¡’õºâcursivš¾9e,‘ÖËthe–°term“rewriter“propAÇer“consists“of“t˜w˜o“functionsŽ¡’õºâof–ÂGtš¾9ypAÇe“ëMAbsVal–¹–->“AbsVal–ÂGºand“ëMContext–¹–->“Contextº,‘í„eac˜hŽ¡’õºâof–qwhicš¾9h“pAÇerforms“m˜ultiple“innermost- rst“simpli cationŽ¡’õºâpasses–N¦with“an“auxiliary“function.‘Ú6When“stabilitš¾9y“is“reac˜hed,Ž¡’õºâit–gômeans“normal“form“has“bAÇeen“ac•¾9hiev“ed.‘OThis–gôsection“dis-Ž¡’õºâcusses–ÛWhoš¾9w“those“auxiliary“functions“w˜ork.‘nxF‘ÿ:«or“simplicit˜y‘ÿ:«,Ž¡’õºâthey–¬!are“treated“as“a“single“function,›ÑÔcalled“ëMsimpº,˜w¾9orkingŽ¡’õºâon–Tthe“union“of“ëMAbsVal“ºand“ëMContextº,“called“ëMTermº.ަ’õºâT‘ÿ:«o–iþmaximise“pAÇerformance,‘)eac¾9h“pass“of“ëMsimp“ºtries“to“do“asŽ¡’õºâm•¾9uc“h–éÑas“pšAÇossible,‘ðso“as“to“minimise“the“n•¾9um“b˜er–éÑof“passesŽ¡’õºârequired.‘€AMeasuremen•¾9ts›6šsho“w“ed˜the˜v‘ÿ|rast˜ma‘ƒŽjorit“y˜of˜termsŽ¡’õºâreac¾9h–Å#normal“form“in“one“pass,‘ñand“no“term“has“bAÇeen“ob-Ž¡’õºâserv¾9ed–Tto“require“more“than“three“passes.ަ’õºâThe–L?individual“rewrite“rules“are“classi ed“in¾9to“groups“(rep-Ž¡’õºâresenš¾9ted–Åïas“lists)“b˜y“the“roAÇot“sym˜bAÇol“of“the“term“whic˜h“theyŽ¡’õºârewrite.‘¼±The–J¿mecš¾9hanism“whic˜h“directs“the“application“ofŽ¡’õºârewrite–ðÖrules“ensures“that“eac¾9h“rule“is“only“applied“to“termsŽ¡’õºâpšAÇossessing–xÈthe“relev‘ÿ|ran¾9t“ro˜ot“sym•¾9b˜ol.‘FÌEac“h–xÈrule“is“imple-Ž¡’õºâmenš¾9ted–Tas“a“function“of“t˜ypAÇe“ëMTerm–¹–->“Maybe“Termº,‘Twhere:ޤÐO’ç¤ëMdata–¹–Maybe“a“=“Nothing“|“Just“aŽ¡’õºâºAs–•bAÇecomes“clear“shortly‘ÿ:«,‘ "wš¾9e“need“to“kno˜w“whether“the“ap-ޤ ’õºâplication–q¡of“a“rewrite“rule“has“had“an¾9y“e ect.‘1VW‘ÿ:«e“couldŽ¡’õºâmak•¾9e›ì6eac“h˜rule˜ha“v“e˜t“ypAÇe˜ëMTerm–¹–->“Term˜ºand˜compare˜theŽ¡’õºâterm–­ bšAÇefore“and“after“application,‘öbut“this“seems“ab˜om-Ž¡’õºâinably–.Œinecienš¾9t,‘tÚbAÇecause“the“rule“itself“\kno˜ws"“when“itŽ¡’õºâhas–¹`made“a“c•¾9hange.‘”Therefore,‘âcw“e–¹`encoAÇde“that“kno¾9wledgeŽ¡’õºâin–³Ythe“return“v‘ÿ|ralue“bš¾9y“passing“bac˜k“ëMNothing“ºif“there“is“noŽ¡’õºâc•¾9hange.‘ÖŽObserv“e–S^that“the“returned“ëMMaybe‘¹–Term“ºv‘ÿ|ralue“is“in-Ž¡’õºâstan•¾9tly›¨“disassem“bled˜using˜a˜Hask“ell˜case˜expression,‘¾Sto˜ ndŽ¡’õºâout–¹whether“the“rule“has“succeeded.‘ä Therefore,‘>a“Hask¾9ellŽ¡’õºâimplemen•¾9tation›íŽwhic“h˜returns˜constructors˜in˜registers,‘õ‚lik“eŽ¡’õºâGlasgo•¾9w›—¦Hask“ell˜[PJ92Ž‘L ],‘¸:nev“er˜actually˜builds˜the˜ëMNothingŽ¡’õºâºor–TëMJust“ºclosure“in“the“heap,“a“pleasing“little“eciency‘ÿ:«.ަ’õºâLet–9oëMt“ºdenote“a“term,‘‚uand“ëMrulesfor(t)“ºdenote“the“list“ofŽ’õºâŸ@‰ff_ÿ Ÿ× ‘ r}Ÿüûró†›Zcmr5°1ŽŽ‘Y±One–5of“the“sharp7er“wits“in“the“functional“programming“commÈãu-ޤnitšÈãy‘ÿZª,–±Èon“reading“an“early“draft,“commen˜ted:ŽŸ ‘€HošÈãw–%could“y˜ou“let“suc˜h“a“w˜onderful“example“of“self-Ž¡‘€reference–Aègo“bšÈãy“unremark˜ed?‘hðI‘AÌthough˜t“it“w˜as“absolutelyŽ¡‘€marvšÈãelous–:that“y˜ou“decided“to“use“an“innermost- rstŽ¡‘€scšÈãheme–A¥in“the“term“rewriter“whic˜h“is,›Xafter“all,˜the“wholeŽ¡‘€p7oinÈãt–øof“Anna's“existance“in“the“Real“W‘ÿZªorld“outside“it-Ž¡‘€self‘!Ž¡ŽŽŽŽŸ’åäº17ŽŽŒ‹²È •ºâ ý? £ ý€‘íºâºrewrite–Мrules“relev‘ÿ|ranš¾9t“to“the“roAÇot“sym˜bAÇol“of“ëMt.“simp(t)“ºisޤ ‘íºâcomputed–Tas“follo¾9ws:Ž©ÐO‘ûç¤ëMsimp(t)Ž¡‘ f=‘¹–schedule(t_inner_simp)Ž¡‘‡’whereŽ¡‘!´Tt_inner_simpŽ¡‘/á=–¹–t“with“simp“applied“to“t's“subtermsŽ¡¡‘ûç¤schedule(t)Ž¡‘ f=–¹–rewrite_with(rulesfor(t),“t)Ž¡¡‘ûç¤rewrite_with([],‘¹–t)Ž¡‘ f=‘¹–tŽ¡¡‘ûç¤rewrite_with((rule:rules),‘¹–t)Ž¡‘ f=–¹–case“(rule“t)“ofŽ¡‘!´TNothing–¹–->“rewrite_with(rules,t)Ž¡‘!´TJust–¹–t2“->“schedule(t2)ަ‘íºâºFirstly‘ÿ:«,›6$ëMtº's–üasubterms“are“simpli ed,˜giving“ëMt_inner_simp.Ž¡‘íºâºThis–"óis“passed“to“inš¾9termediary“ëMscheduleº,‘f[whic˜h“examinesŽ¡‘íºâthe–ƒ¼rošAÇot“sym¾9b˜ol“to“determine“the“relev‘ÿ|ran¾9t“list“of“rewriteŽ¡‘íºârules.‘ )OëMschedule–ÄIºpasses“the“rules“and“its“argumen¾9t“toŽ¡‘íºâëMrewrite_withº,‘™¬whic•¾9h›zÂw“orks˜its˜w“a“y˜through˜the˜list˜of˜rules.Ž¡‘íºâIf–2ºit“runs“out“of“rules,‘` it“simply“returns“the“term.‘ÐçBut“if“thereŽ¡‘íºâis–Þ a“rule,‘é‘it“is“applied“to“the“term.‘ 4This“either“has“no“e ect,Ž¡‘íºâin–÷whic¾9h“case“the“next“rule“is“tried,‘/‚or“it“proAÇduces“a“newŽ¡‘íºâterm–'eëMt2º.‘R¢Noš¾9w“ëMt2“ºma˜y“w˜ell“ha˜v˜e“a“di eren˜t“roAÇot“sym˜bAÇol,Ž¡‘íºâwhic•¾9h›¶Ýw“ould˜in“v‘ÿ|ralidate˜all˜the˜remaining˜rules.‘üóSo˜rewritingŽ¡‘íºâof–TëMt2“ºis“con•¾9tin“ued›Tb“y˜passing˜it˜bac“k˜to˜ëMscheduleº.ŽŸ ‘íºâThe–mnet“e ect“of“ëMschedule(t)“ºis“thš¾9us“to“k˜eep“applyingŽ¡‘íºârewrite–¯„rules“to“the“roAÇot“of“ëMt“ºun¾9til“no“applicable“rules“canŽ¡‘íºâbšAÇe–5¢found.‘ }ZThis“pro˜cess“deals“prop˜erly“with“c¾9hanges“inŽ¡‘íºâthe–ôrošAÇot“sym•¾9b˜ol.‘¸®Observ“e–ôthat“the“call“to“ëMschedule“ºfromŽ¡‘íºâëMrewrite_with–HSºis“not“necessary“for“correctness.‘µmW‘ÿ:«e“couldŽ¡‘íºâsimply–+´return“ëMt2“ºat“this“pAÇoinš¾9t.‘ÎWhat“this“w˜ould“mean“is“thatŽ¡‘íºâanš¾9y–8ípAÇossible“rewrites“of“ëMt2“ºw˜ould“bAÇe“dela˜y˜ed“un˜til“the“nextŽ¡‘íºâsimpli cation–7Îpass,‘drather“than“bAÇeing“done“straighš¾9t“a˜w˜a˜y‘ÿ:«.‘Ò™SoŽ¡‘íºâomitting–~the“re-sc¾9hedule“implies“more“simpli cation“passesŽ¡‘íºâand–Ta“serious“loss“of“eciency‘ÿ:«.ŽŸ5‘íºâ¹4.3Ž‘G·Dealing–LÎwith“lambFfdas“and“applicationsŽŸm‘íºâºThe–éŸpresence“of“ëMAbsLamº,‘^²ëMAbsAp“ºand“ëMAbsVar“ºterms“in¾9tro-Ž¡‘íºâduces–Ö?the“need“to“pšAÇerform“lam¾9b˜da“calculus-lik¾9e“substi-Ž¡‘íºâtution.‘ *What–çfollo¾9ws“applies“equally“to“the“dual“con-Ž¡‘íºâstructions–°ªëMCtxLamº,‘—ëMCtxAp“ºand“ëMCtxVarº.‘îsIn“particular,Ž¡‘íºâëMsimp–|Uºneeds“to“bAÇe“able“to“deal“with“terms“of“the“formŽ¡‘íºâëM(AbsAp–¹–(AbsLam“v“e)“a)º.‘ pNaturally‘ÿ:«,‘‚wš¾9e–Ûàcan“reac˜h“di-Ž¡‘íºârectly–Béfor“the“blunderbuss“solution:‘ w™devise“a“functionŽ¡‘íºâëMsubst(e,v,a)–Xžºto“replace“free“oAÇccurrences“of“ëMv“ºin“ëMe“ºwith“ëMa,Ž¡‘íºâºand–Templo¾9y“it“in“the“rewrite“rule:ަ‘ûç¤ëMAbsAp–¹–(AbsLam“v“e)“a–,Â===>“subst(e,v,a)ަ‘íºâºTwš¾9o–Adefects“are“apparen˜t.‘ ðFirstly‘ÿ:«,‘L‰since“ëMsimp“ºis“committedŽ¡‘íºâto–8Ðdoing“innermost- rst“simpli cation,‘dëbAÇoth“function“and“ar-Ž¡‘íºâgumenš¾9t–B–are“simpli ed“extensiv˜ely“bšAÇefore“substitution“b˜egins.Ž¡‘íºâOur–­ßhands“are“noš¾9w“tied:‘èµw˜e“cannot“mak˜e“the“lam˜bAÇda/applyŽ¡‘íºâterm–ãereduction“an¾9y“lazier.‘†¤Ineciency“is“the“second“com-Ž¡‘íºâplain•¾9t.‘0‹This›q]sc“heme˜demands˜a˜complete˜substitution˜passŽ¡‘íºâo•¾9v“er–TëMe“ºfor“evš¾9ery“argumen˜t.ŽŽŽ ý€’õºâAn–R±altogether“nicer“solution“is“to“forget“abAÇout“ëMsubst“ºand“theޤ ’õºârewrite–»drule.‘ŸInstead,‘äèwš¾9e“equip“ëMsimp“ºwith“an“en˜vironmen˜tŽ¡’õºâëMenv–?oºwhic¾9h“binds“ëMAbsº-v›ÿ|rariables“to“v˜alues.‘šÀNo•¾9w,‘‰õgiv“e‘?oëMsimpŽ¡’õºâºa–©couple“of“spAÇecial“cases.‘ØöThese“omit“the“usual“simpli ca-Ž¡’õºâtion–›·of“subterms,‘½Oand“bš¾9ypass“the“general“rewriting“mec˜ha-Ž¡’õºânism.‘¥6In–˜Athis“w•¾9a“y›˜Aw“e˜regain˜precise˜con“trol˜o“v“er˜the˜orderŽ¡’õºâof–ý×rewrites,‘‰and“no“separate“substitution“passes“are“needed.Ž¡’õºâV‘ÿ:«ariables–Tare“simply“loAÇok¾9ed“up:ޤÐO’ç¤ëMsimp–¹–env“(AbsVar“v)“=“env“vŽ¡’õºâºOn–Ýencounš¾9tering“ëM(AbsAp–¹–f“a)º,‘îw˜e–Ýneed“to“try“and“turn“ëMfޤ ’õºâºinš¾9to– ³an“ëM(AbsLam–¹–v“e)º.‘>The– ³ob˜vious“w˜a˜y“to“do“this“is“b˜yŽ¡’õºâapplying–ôÒëMsimp“ºto“ëMfº,‘ûSbut“this“wš¾9ould“bAÇe“a“big“w˜aste“of“time“ifŽ¡’õºâëMf–×ãºis“in“that“form“already‘ÿ:«.‘õSo“there“is“a“spAÇecial“c•¾9hec“k–×ãfor“thisŽ¡’õºâcase.‘‰¼The›ämen•¾9vironmen“t˜is˜then˜augmen“ted˜with˜a˜bindingŽ¡’õºâfor–³¹ëMvº,‘ÛRand“simpli cation“con•¾9tin“ues–³¹with“ëMeº.‘÷žBy“c¾9hoAÇosing“toŽ¡’õºâbind–íÉëMv“ºto“ëMa“ºor“ëMsimp–¹–env“aº,‘õ²w¾9e–íÉcan“again“v‘ÿ|rary“the“strictnessŽ¡’õºâof–y;the“scš¾9heme.‘H$The“latter“c˜hoice“giv˜es“bšAÇetter“p˜erformance,Ž¡’õºâso–Tthe“spAÇecial“case“for“ëM(AbsAp–¹–f“a)‘Tºis:Ž©ÐO’ç¤ëMsimp–¹–env“(AbsAp“f“a)Ž¡’f=–¹–let“sa“=“simp“env“aŽ¡’.mêsf–¹–=“simp“env“fŽ¡’‡’inŽ¡’‡’case–¹–f“ofŽ¡’)´TAbsLam–¹–v“eŽ¡’7á->–¹–simp“env{v“:->“sa}“eŽ¡’)´TotherŽ¡’7á->–¹–case“sf“ofŽ¡’T:šAbsLam–¹–v2“e2Ž¡’bg\->–¹–simp“env{v2“:->“sa}“e2Ž¡’T:šotherŽ¡’bg\->–¹–AbsAp“sf“saަ’õºâºIf–òÁëMf“ºsimply“refuses“to“bAÇe“rewritten“in¾9to“an“ëMAbsLamº,‘ù«the“termŽ¡’õºâhas–,òits“subterms“simpli ed“and“is“then“returned“as-is.‘cJThisŽ¡’õºâis–Dzconsistenš¾9t“with“ho˜w“normal“cases“are“dealt“with,‘CsinceŽ¡’õºâthere–Tare“no“more“ëMAbsAp“ºrewrite“rules.ŽŸ ’õºâAn–—-ëMAbsVar“ºconstruct“can“refer“not“just“to“v‘ÿ|rariables“bAÇoundŽ¡’õºâb¾9y–=‹a“surrounding“ëMAbsLamº,‘‡˜but“also“to“the“abstract“v‘ÿ|raluesŽ¡’õºâof–6/other“functions.‘T‘ÿ:«o“deal“with“these,‘~fw¾9e“\preload"“theŽ¡’õºâëMAbsº-en•¾9vironmen“t–°Fwith“suitable“bindings“bAÇefore“starting“sim-Ž¡’õºâpli cation.‘}òFinally‘ÿ:«,‘èŸnote–‹*that“the“dual“ëMCtxº-constructionsŽ¡’õºâare–ü¿dealt“with“in“the“same“w•¾9a“y‘ÿ:«,‘6™so–ü¿ëMsimp“ºcarries“t•¾9w“o‘ü¿en“vi-Ž¡’õºâronmen¾9ts,‘HËrather–>€than“just“one.‘—óThe“only“di erence“is“thatŽ¡’õºâa–þëMCtxVar“ºcan“only“refer“to“ëMCtxLam“ºbAÇound“v‘ÿ|rariables.‘nTheseŽ¡’õºât•¾9w“o›rÙen“vironmen“ts˜are˜henceforth˜referred˜to˜as˜ëMaenv˜ºandŽ¡’õºâëMcenv‘TºrespAÇectiv¾9ely‘ÿ:«.ŽŸ5’õºâ¹4.4Ž’ G·Avoiding–LÎin nite“b¹™ranchingޤm’õºâ4.4.1Ž’úíA–LÎnaive“app¹™roachŽ¡’õºâºSection–323.4“in¾9troAÇduced“the“ëMCaseU›3*ºand“ëMCaseUU˜ºconstructionsޤ ’õºâas–¹yone“of“the“fundamenš¾9tal“mec˜hanisms“for“disassem˜blingŽ¡’õºâconš¾9texts.‘uA‘‡Øserious–ˆ8problem“whic˜h“bAÇecomes“apparen˜t“asŽ¡’õºâsošAÇon–UÄas“one“starts“ xp˜oin¾9ting“is“the“p˜oten¾9tial“for“in niteŽ¡’õºâbranc•¾9hing.‘pFixpšAÇoin“ting–Tpro˜duces“expressions“lik¾9eަ’ç¤ëMCaseU–¹–e“(CaseU“e“w“x)“(CaseU“e“y“z)ަ’õºâºwhicš¾9h–Tis“equiv‘ÿ|ralen˜t“to:ŽŽŽŽŽŸ’åä18ŽŽŒ‹Ó¦ •ºâ ý? £ ý€‘ûç¤ëMCaseU–¹–e“w“zŽ©ÐO‘íºâºW‘ÿ:«e–¶©can“get“round“this“b¾9y“designing“the“normal“form“so“thatޤ ‘íºâfor– ±a“term“ëM(CaseU–¹–e“a“b)º,‘ Ÿneither– ±subterm“ëMa“ºnor“ëMb“ºma¾9y“doŽ¡‘íºâa–fÕëMCaseU‘fÀºon“ëMeº.‘òT‘ÿ:«o“ac•¾9hiev“e–fÕthis“normalisation“requires“usingŽ¡‘íºâpartial–˜fkno¾9wledge“abAÇout“the“v‘ÿ|ralue“of“ëMe“ºwhen“simplifying“ëMaŽ¡‘íºâºand‘TëMbº.ŽŸ ‘íºâT‘ÿ:«o–@óimplemenš¾9t“this,‘‹Úw˜e“could“adopt“the“follo˜wing“sc˜heme.Ž¡‘íºâGivš¾9e–^#ëMsimp“ºy˜et“another“en˜vironmen˜t,–°VëMselenvº,“whic˜h‘^#mapsŽ¡‘íºâswitc¾9h–…expressions“seen“in“surrounding“ëMCaseU‘„ÿºand“ëMCaseUUsŽ¡‘íºâºto–N"partial“information“abAÇout“their“v‘ÿ|ralue.‘ÆÚWhen“a“nestedŽ¡‘íºâëMCase–s ºexpression“is“encounš¾9tered,‘‹3loAÇok“up“its“switc˜h“v‘ÿ|ralue“inŽ¡‘íºâëMselenvº.‘`¥If–,there“is“a“correspAÇonding“en¾9try‘ÿ:«,‘1¿this“ëMCase“ºexpres-Ž¡‘íºâsion–¿›mš¾9ust“bAÇe“examining“a“con˜text“whic˜h“has“already“bAÇeenŽ¡‘íºâloAÇokš¾9ed–—Öat,‘¸vso“the“ëMCase“ºexpression“is“replaced“b˜y“whic˜hev˜erŽ¡‘íºâarm–é;the“table“enš¾9try“sa˜ys“is“correct.‘˜$F‘ÿ:«or“example,‘4giv˜en“aŽ¡‘íºâcallަ‘ûç¤ëMsimp–¹–selenv“(CaseU“e“(CaseU“e“w“x)“(CaseU“e“y“z))ަ‘íºâºsimpli cation–,Ëof“ëM(CaseU–¹–e“w“x)–,˺is“done“with“ëMselenv“ºbindingŽ¡‘íºâëMe–/ƒºto“ëMStop1º,‘]zand“simpli cation“of“ëM(CaseU–¹–e“y“z)–/ƒºis“done“withŽ¡‘íºâëMselenv–`Lºbinding“ëMe“ºto“some“v‘ÿ|ralue“of“the“form“ëMUp1‘¹–[...]º.‘àThisŽ¡‘íºâpartial–_$information“abAÇout“ëMe“ºimmediately“allo¾9ws“the“systemŽ¡‘íºâto–‡(reduce“the“t•¾9w“o–‡(subterms“to“ëMw“ºand“ëMz“ºrespAÇectiv¾9ely‘ÿ:«.‘qìProp-Ž¡‘íºâagation–ûìof“information“abAÇout“ëMCaseUU‘ûåºselector“v‘ÿ|ralues“is“doneŽ¡‘íºâanalogously‘ÿ:«.ŽŸ ‘íºâëMselenv–(cºis“augmenš¾9ted“eac˜h“time“a“ëMCaseU›(^ºor“ëMCaseUU˜ºis“\goneŽ¡‘íºâpast".‘ ?îA‘Ë problem–ËÓis“what“happAÇens“when“w¾9e“go“pastŽ¡‘íºâa›ÙÍëM(CtxLam–¹–v“e)º,‘Jësince˜this˜w•¾9ould˜in“v‘ÿ|ralidate˜an“y˜k“eys˜inŽ¡‘íºâëMselenv–9ºconš¾9taining“free“v‘ÿ|rariable“ëMvº.‘" Remem˜bAÇer“that“the“k˜eysŽ¡‘íºâare–üarbitrary“expressions,‘5²rather“than“mere“v‘ÿ|rariables.‘ІAnŽ¡‘íºâexpAÇensivš¾9e–£Wsolution“is“to“ lter“out“all“(k˜ey‘ÿ:«,‘º$v‘ÿ|ralue)“pairs“whic˜hŽ¡‘íºârefer–àœto“ëMvº,‘nbut“that's“o•¾9v“erkill.‘~HIt–àœis“c¾9heapAÇer“to“completelyŽ¡‘íºâemptš¾9y–{°ëMselenv“ºat“ev˜ery“ëMCtxLamº.‘O„This“doAÇesn't“lose“informa-Ž¡‘íºâtion–kbAÇecause“the“abstract“inš¾9terpreter“nev˜er“builds“con˜textŽ¡‘íºâexpressions–÷ewhere“wš¾9e“need“to“main˜tain“selector“informationŽ¡‘íºâacross–”’ëMCtxLam“ºbAÇoundaries.‘ñ…F‘ÿ:«or“example,‘®Sit“nevš¾9er“builds“an˜y-Ž¡‘íºâthing‘Tlik¾9e:ަ‘ûç¤ëMCaseU–¹–s1“(\c1“->“...“(CaseU“s2“....))Ž¡‘&mê(\c2–¹–->“...“(CaseU“s2“....))ŽŸ5‘íºâ¹4.4.2Ž‘ úíGeneralising–LÎthe“schemeŽŸm‘íºâºA‘œ›little–œ¾thoughš¾9t“sho˜ws“our“solution,‘¾˜whilst“pAÇerfectly“w˜ork-Ž¡‘íºâable,‘µDis–@toAÇo“wš¾9eak.‘ôiW‘ÿ:«e“need“a“more“general“w˜a˜y“to“propagateŽ¡‘íºâso-called–ëá\ëMselenv“ºinformation"“around,‘!„as“can“bAÇe“seen“b¾9yŽ¡‘íºâconsidering:ަ‘ûç¤ëMCMeet–¹–[e,“UpUp2“[Stop1,“Stop1]]ަ‘íºâºInitially‘ÿ:«,‘Òit–¬UlošAÇoks“lik¾9e“nothing“more“can“b˜e“done“with“this.Ž¡‘íºâBut–®if,›ab¾9y“loAÇoking“in“ëMselenvº,˜wš¾9e“can“sho˜w“that“ëMe“ºhas“anŽ¡‘íºâëMUpUp2‘¹–[...]–Tºv‘ÿ|ralue,“then:ަ‘ZÐëMCMeet–¹–[e,“UpUp2“[Stop1,“Stop1]]Ž¡‘ûç¤=–¹–UpUp2“[Stop1,“Stop1]ަ‘íºâºWhat–}twš¾9e“really“need“is“a“general“mec˜hanism“for“propagat-Ž¡‘íºâing–ÓTëMselenv“ºinformation.‘VqT‘ÿ:«o“bAÇe“fully“general,‘Ôwš¾9e“will“ha˜v˜eŽ¡‘íºâto–W¯searcš¾9h“ëMselenv“ºfor“eac˜h“term“ëMsimp“ºencoun˜ters.‘ã€This“pro-Ž¡‘íºâcess–ÆÀcan“bAÇe“rolled“inš¾9to“the“general“mec˜hanism“of“ëMsimpº,‘ób˜yŽŽŽ ý€’õºâsearc¾9hing–«ÄëMselenv“ºafter“ëMsimp“ºruns“out“of“applicable“rewriteޤ ’õºârules.‘5ÂW‘ÿ:«e–ÅexpšAÇect“to“disco•¾9v“er–Ånothing“ab˜out“the“v‘ÿ|rast“ma-Ž¡’õºâjoritš¾9y–Xµof“terms,‘iin“whic˜h“case“ëMsimp“ºacts“as“bAÇefore.‘æ’But,‘iforŽ¡’õºâa–luc¾9ky“few,‘? ëMselenv“ºtells“us“a“little“abAÇout“the“term:‘øÉit“isŽ¡’õºâeither›>jëMStop1º,–ˆ°ëMStop2º,“ëMUp2º,“ëMUp1–¹–[...]˜ºor˜ëMUpUp2“[...]º.‘—³InŽ¡’õºâthe–¼Ô rst“three“cases,‘·wš¾9e“can“ob˜viously“replace“the“term“withŽ¡’õºâthe–relev›ÿ|ran¾9t“v˜alue,‘õbut“the“other“t•¾9w“o–are“problematic.‘'Ho¾9wŽ¡’õºâcan–y wš¾9e“exploit“partial“information“lik˜e“this?‘G™Conceptually‘ÿ:«,Ž¡’õºâwš¾9e–%need“to“add“a“foAÇotnote“to“the“v‘ÿ|ralue“sa˜ying,‘ ûfor“example,Ž¡’õºâ\P‘ÿ:«.S.–)£This“v‘ÿ|ralue“is“kno¾9wn“to“bšAÇe“ëMUpUp2‘¹–[...]º",‘.·and“mo˜difyŽ¡’õºâthe–Trewrite“rules“to“takš¾9e“accoun˜t“of“suc˜h“foAÇotnotes.ŽŸ ’õºâThis–LHall“sounds“rather“clumsy‘ÿ:«,‘Zbut“there“is“a“neat“solution.Ž¡’õºâRecall– qsection“3.4“in¾9troAÇduced“ëMDefU‘ 1ºand“ëMDefUUº.“ëMDefºs“standŽ¡’õºâfor–Ÿg\de nitely",‘¶ýand“are“inš¾9tended“as“a“w˜a˜y“of“attac˜hing“suc˜hŽ¡’õºâa–TèfoAÇotnote“to“a“v‘ÿ|ralue.‘Û-The“in•¾9tuitiv“e–Tèreading“of“ëM(DefU‘¹–e)“ºisŽ¡’õºâ\I'm–†not“sure“what“the“exact“v‘ÿ|ralue“of“ëMe“ºis,‘¢¾but“I‘…ódo“kno¾9w“it'sŽ¡’õºâan–zòëMUp1‘¹–[...]“ºv‘ÿ|ralue".‘MISo“noš¾9w,‘”Yon“disco˜v˜ering“from“ëMselenvŽ¡’õºâºthat–x¶a“term“ëMc“ºhas“an“ëMUp1›¹–[...]“ºor“ëMUpUp2˜[...]“ºv‘ÿ|ralue,‘‘Žw¾9eŽ¡’õºâmerely–èµneed“to“wrap“ëMc“ºin“ëMDefU›è~ºor“ëMDefUU˜ºrespAÇectiv¾9ely‘ÿ:«.‘–“AllŽ¡’õºâthat–’/remains“to“do“is“moAÇdify“rewrite“rules“to“takš¾9e“accoun˜t“ofŽ¡’õºâëMDefU–BHºand›BTëMDefUU“ºas˜appropriate.‘£pThis˜mec¾9hanism˜subsumesŽ¡’õºâthe–Tprevious“one.‘pConsider“again:Ž©½ì’ç¤ëMsimp‘¹–selenvŽ¡’‡’(CaseU–¹–e“(CaseU“e“w“x)“(CaseU“e“y“z))ަ’õºâºIgnoring–‚ÀpAÇossible“c¾9hanges“to“ëMwº,–žëMxº,“ëMy–‚Àºand“ëMzº,‘žëMsimp“ºtranformsŽ¡’õºâthis‘Tto:ަ’ç¤ëMCaseU–¹–e“(CaseU“Stop1“w“x)“(CaseU“(DefU“e)“y“z)ަ’õºâºApplication–Tof“the“rewrite“rulesަ’ç¤ëMCaseU–¹–Stop1‘æXa“b–,Â===>“aŽ¡’ç¤CaseU–¹–(DefU“e)“a“b–,Â===>“bަ’õºâºyields–Tthe“desired“result:ަ’ç¤ëMCaseU–¹–e“w“zަ’õºâºRecall–&the“other“example,‘j,in“whic¾9h“ëMselenv“ºbinds“ëMe“ºto“anŽ¡’õºâëMUpUp2‘¹–[...]‘Tºv‘ÿ|ralue:ަ’ç¤ëMCMeet–¹–[e,“UpUp2“[Stop1,“Stop1]]ަ’õºâºAfter–Î}wrapping“ëMDefUU‘ÎMºaround“ëMeº,‘üÇthe“follo¾9wing“sequence“ofŽ¡’õºârewrites–Tis“pAÇossible:ަ’ ZÐëMCMeet–¹–[DefUU“e,“UpUp2“[Stop1,“Stop1]]Ž¡¡’ç¤=–¹–UpUp2“[“CMeet“[SelUU“1“e,“Stop1],Ž¡’3'€CMeet–¹–[SelUU“2“e,“Stop1]“]Ž¡¡’ç¤=–¹–UpUp2“[Stop1,“Stop1]ަ’õºâºAgain,‘ôåthe–È/desired“result“is“obtained.‘5All“w¾9e“had“to“do“isŽ¡’õºâinclude–Ta“rewrite“rule“deriv¾9ed“from“this:ަ’ç¤ëMCMeet–¹–[“UpUp2“[x1,“x2],‘ s,UpUp2“[y1,“y2]“]Ž¡’f===>‘,ÂUpUp2–¹–[“CMeet“[x1,“y1],Ž¡’Xô0CMeet–¹–[x2,“y2]“]ަ’õºâºBy–\ŸmoAÇdifying“the“rule“so“that“one“of“the“initial“terms“isŽ¡’õºâëM(DefUU‘¹–e)º,‘ÛHand–ÌÄbAÇearing“in“mind“the“meanings“of“ëMDefUU‘̲ºandŽ¡’õºâëMSelUU–Tº(see“section“3.4),“one“can“easily“sho¾9w“that:ŽŽŽŽŽŸ’åä19ŽŽŒ‹îs •ºâ ý? £ ý€‘ûç¤ëMCMeet–¹–[“DefUU“e,‘ s,UpUp2“[y1,“y2]“]ޤ ‘ f===>‘,ÂUpUp2–¹–[“CMeet“[SelUU“1“e,“y1],Ž¡‘Pô0CMeet–¹–[SelUU“2“e,“y2]“]Ž©ÐO‘íºâºAll–™in“all,‘ú‰a“rather“eleganš¾9t“solution“to“a“tric˜ky“problem.Ž¡‘íºâThere–Tis“just“one“ nal“ca•¾9v“eat.‘pConsider:ަ‘ûç¤ëMsimp–¹–selenv“(CaseU“e“a“b)ަ‘íºâºIf–ùFw¾9e“cannot“ nd“a“v‘ÿ|ralue“for“ëMe“ºin“ëMselenvº,‘þãthe“ëMCaseU‘ù?ºexpres-Ž¡‘íºâsion–Í—maš¾9y“still“bAÇe“remo˜v‘ÿ|rable“b˜y“the“follo˜wing“means.‘E:FindŽ¡‘íºâin–ÔëMselenv“ºa“kš¾9ey“ëMk“ºfor“whic˜h“w˜e“can“pro˜v˜e“that“ëMkŽ‘ëPv‘zgëMeŽ‘ 3ýº,Ž¡‘íºâand–æ(for“whic¾9h“ëMk“ºis“bAÇound“to“some“ëMUp1‘¹–[...]“ºv‘ÿ|ralue.‘ŽìSo“ëMeŽ¡‘íºâºmš¾9ust–&also“bind“to“some“ëMUp1‘¹–[...]“ºv‘ÿ|ralue,‘*Cso“w˜e“can“replaceŽ¡‘íºâëM(CaseU–¹–e“a“b)–àºb¾9y“ëM(CaseU–¹–(DefU“e)“a“b)º.‘'ëMCaseUUºs‘àare,‘ÃasŽ¡‘íºâev•¾9er,‘W¬analogous.‘»ªSo›Jgw“e˜migh“t˜bAÇe˜able˜to˜do˜just˜a˜little˜bitŽ¡‘íºâbAÇetter– ¼mš¾9y“taking“monotonicit˜y“of“k˜eys“in˜to“accoun˜t“whenŽ¡‘íºâsearc¾9hing‘TëMselenvº.ŽŸ5‘íºâ¹4.5Ž‘G·Avoiding–LÎan“expFfonential“explosionŽŸm‘íºâºAlthough–4¶wš¾9e“ha˜v˜e“a˜v˜oided“non-termination“via“in niteŽ¡‘íºâbrancš¾9hing,‘ïŠanother–³insidious“problem“lurks:‘.terms“whic˜hŽ¡‘íºâexpand–™,expšAÇonen¾9tially“for“a“while,‘º"b˜efore“shrinking“bac¾9k“toŽ¡‘íºâa–#compact“normal“form.‘ÝSucš¾9h“bAÇeha˜viour“causes“the“termŽ¡‘íºârewriter–Âlto“run“out“of“memory“simplifying“seemingly“in-Ž¡‘íºâsigni can¾9t–¸expressions.‘yThe“problem“manifests“itself,‘à­onceŽ¡‘íºâagain,‘nŸwith–\ÃëMCaseU›\±ºand“ëMCaseUU˜ºterms.‘ò¾The“normal“form“re-Ž¡‘íºâquires–ª¸that“the“switc¾9h“expression“cannot“itself“bAÇe“a“ëMCaseU‘ªºorŽ¡‘íºâëMCaseUUº,–Tgiving“rise“to“some“rules“of“the“form:ަ‘ûç¤ëMCaseUU–¹–(CaseUU“a“b“c“d)“e“f“gŽ¡‘ûç¤===>Ž¡‘ûç¤CaseUU–¹–a“(CaseUU“b“e“f“g)Ž¡‘&mê(CaseUU–¹–c“e“f“g)Ž¡‘&mê(CaseUU–¹–d“e“f“g)ަ‘íºâºThe–Ðzproblem“ošAÇccurs“b˜ecause“of“the“w•¾9a“y–ÐzëMrewrite_with“ºat-Ž¡‘íºâtempts–ž5to“apply“rewrite“rules“to“the“roAÇot“term“un¾9til“no“moreŽ¡‘íºâcan–ËbAÇe“found.‘óÔIf“ëMa“ºis“itself“a“ëMCaseUU‘Œºterm,‘DhëMrewrite_withŽ¡‘íºâºwill–îéimmediately“reapply“the“rule,‘¥Mtrebling“the“expres-Ž¡‘íºâsion–Æÿsize“again.‘ 1rIt“w¾9ould“bšAÇe“b˜etter“to“lo˜ok“to“see“ifŽ¡‘íºâw¾9e–åâcan“do“some“simpli cations“on“the“ëM(CaseUU–¹–b“e“f“g)º,Ž¡‘íºâëM(CaseUU–¹–c“e“f“g)–køºand“ëM(CaseUU–¹–d“e“f“g)–køºterms“ëRb•‡efor“e‘køºse-Ž¡‘íºâlecting–FÖanother“rewrite“rule“for“the“roAÇot“term.‘°öThere's“aŽ¡‘íºâv¾9ery›yZgo•AÇo“d˜c•¾9hance˜w“e˜can,‘˜bAÇecause˜it˜is˜lik“ely˜that˜w“e˜alreadyŽ¡‘íºâkno¾9w–üËenough“abšAÇout“ëMbº,‘³ëMc“ºand“ëMd“ºto“eliminate“their“asso˜ciatedŽ¡‘íºâëMCaseUUºs.‘iÙIt–/"ma¾9y“also“turn“out“that“ëMa“ºis“the“same“as“ëMbº,‘5•ëMc“ºorŽ¡‘íºâëMdº,–Tand“this“is“helpful“toAÇo.ŽŸ ‘íºâImplemenš¾9ting–oÍthis“is“not“only“easy‘ÿ:«,‘Æjbut“essen˜tial.‘+ÚWhenŽ¡‘íºâëMrewrite_with–I$ºdetects“that“a“rewrite“rule“has“created“aŽ¡‘íºâëMCaseUU‘3ºterm,‘»Îit–4doAÇes“not“immediately“seek“out“anotherŽ¡‘íºârewrite–àarule“for“the“roAÇot“term.‘}–Instead,‘$it“tries“to“rewriteŽ¡‘íºâthe–’subterms“as“m•¾9uc“h–’as“pšAÇossible,‘¬Âand“only“then“lo˜oks“againŽ¡‘íºâat–3“Dt)Ž¡’f=‘¹–FalseŽ¡¡’ç¤unit_value–¹–(Lift‘ s,(D1“x“...“x“Dn))Ž¡’f=–¹–ANonRec“[unit_value(D1)“...“unit_value(Dn)]Ž¡¡’ç¤unit_value–¹–(Lift2“(D1“x“...“x“Dn))Ž¡’f=–¹–ARec‘æX[unit_value(D1)“...“unit_value(Dn)]ަ’õºâºThis–T—wš¾9orks“ ne,–¤gbut,“as‘T—usual,“w˜e–T—can“do“a“little“bAÇetter.Ž¡’õºâPresenš¾9ted–&with“a“term“already“compAÇosed“en˜tirely“of“ëMARecŽ¡’õºâºand–•øëMANonRecºs,‘¯qthe“scš¾9heme“returns“a“cop˜y“of“the“term,‘¯qgivingŽ¡’õºâa–k pšAÇoten¾9tial“loss“of“sharing.‘‘A‘j±small“mo˜di cation“detectsŽ¡’õºâsuc¾9h–Tterms“and“returns“them“as-is.ŽŸ€’õºâ¹4.7Ž’ G·Impš¹™roving–LÎthe“rep˜resentation“of“contexts:‘fhëMApplyETŽŸm’õºâºF‘ÿ:«or–;tmanš¾9y“trivial-loAÇoking“functions,‘Düthe“abstract“in˜terpreterŽ¡’õºâemits–wa“remark‘ÿ|rably“cumš¾9bAÇersome“and“unin˜tuitiv˜e-loAÇokingŽ¡’õºâterm.‘ÝÂExamination–YJof“terms“from“ rst“order“functions“sho¾9wsŽ¡’õºâa›èsw•¾9a“y˜to˜cut˜do“wn˜their˜sizes.‘ zSince˜all˜abstract˜v‘ÿ|ralues˜pAÇer-Ž¡’õºâtaining–à¶to“the“argumen¾9ts“and“result“of“a“ rst“order“functionŽ¡’õºâare–H unitary‘ÿ:«,‘T·the“only“thing“one“can“ask“abAÇout“it“is“ho¾9w“theŽ¡’õºâconš¾9text–˜ùon“the“result“propagates“to“eac˜h“argumen˜t.‘òüSuppAÇos-Ž¡’õºâing–“Õwš¾9e“ha˜v˜e“ëMfº,‘­¼a“ rst“order“function“of“óO5ùž" cmmi9ëOm“ºargumen˜ts,‘­¼and“w˜eŽ¡’õºâw•¾9an“t–^to“knoš¾9w“what“con˜text“propagates“to“the“ëOnº'th“argumen˜tŽ¡’õºâif–aØthe“result“is“demanded“in“conš¾9text“ëMalphaº.‘ýA˜t“presen˜t,‘túw˜eŽ¡’õºâget–Ta“large“term“of“the“form:ަ’ç¤ëMCtxAp‘ s,(FvalC–¹–(AbsAp“(GetA“...“(AbsAp“(FvalA“f)Ž¡’¼-~a1)Ž¡’ƒzv...Ž¡’kÚˆai)Ž¡’$ú¾))Ž¡¡’$ú¾(Fnc–¹–aj“...“(Fnc“am“alpha)“...)ަ’õºâºwhere‘“áëMiŽ› ²(º=‘d±ëOn–b–ëP“º1–“áand“ëMjŽ˜º=‘d±ëOn–b–º+“1.‘˜What–“áthis“doAÇes“it“to“useŽ¡’õºâthe›©ªëM(AbsAp–¹–(GetA“...))˜ºconstruction˜ëOn–6äëP“º1˜times˜to˜supplyŽ¡’õºâthe–w rst“ëOn–OëP“º1–wabstract“v‘ÿ|ralue“argumen•¾9ts,‘€whic“h–wexpAÇoses“theŽŽŽŽŽŸ’åä20ŽŽŒ‹ Ö •ºâ ý? £ þ§þ ÿi€‘íºâ ÿefg‰fföÌÌŸÿþÌÍ )³4„0³2ff þäÿþ‘33ëMFsqDiffޤ ‘ ìÉ=–¹–(Fval“(\c1“->“(CJOINŽ¡‘^ùU(ApplyET#0–¹–F+“(ApplyET#1“F*“(FncC“(FncC“c1))))Ž¡‘^ùU(ApplyET#0–¹–F-“(ApplyET#0“F*“(FncC“(FncC“c1))))))Ž¡‘/¹y(\a1–¹–->“(Fval“(\c2“->“(CJOINŽ¡’¡‰(ApplyET#1–¹–F+“(ApplyET#1“F*“(FncC“c2)))Ž¡’¡‰(ApplyET#1–¹–F-“(ApplyET#0“F*“(FncC“c2)))))Ž¡‘qß­(\a2–¹–->“(ANonRec“[])))))Ž¡¡‘33FsqDiffŽ¡‘ ìÉ=–¹–(Fval“(\c1“->“(CJOINŽ¡‘^ùU{(FvalC‘¹–F+)Ž¡‘c²ë(Fnc–¹–(ANonRec“[])“(Fnc“(ANonRec“[])“{(FvalC“{*(FvalA“F*)“(ANonRec“[])*})Ž¡’…™(Fnc–¹–(ANonRec“[])“(FncC“(FncC“c1)))}))}Ž¡‘^ùU{(FvalC‘¹–F-)Ž¡‘c²ë(Fnc–¹–(ANonRec“[])“(Fnc“(ANonRec“[])“{(FvalC“F*)Ž¡’…™(Fnc–¹–(ANonRec“[])“(Fnc“(ANonRec“[])Ž¡’2(FncC–¹–(FncC“c1))))}))}))Ž¡‘/¹y(\a1–¹–->“(Fval“(\c2“->“(CJOINŽ¡’¡‰{(FvalC–¹–{*(FvalA“F+)“(ANonRec“[])*})Ž¡’¥Ù(Fnc–¹–(ANonRec“[])“{(FvalC“{*(FvalA“F*)“(ANonRec“[])*})Ž¡’ÿŸA(Fnc–¹–(ANonRec“[])“(FncC“c2))})}Ž¡’¡‰{(FvalC–¹–{*(FvalA“F-)“(ANonRec“[])*})Ž¡’¥Ù(Fnc–¹–(ANonRec“[])“{(FvalC“F*)Ž¡’ÿŸA(Fnc–¹–(ANonRec“[])“(Fnc“(ANonRec“[])“(FncC“c2)))})}))Ž¡‘qß­(\a2–¹–->“(ANonRec“[])))))ŽŸ‘^®rºFigure–T1:‘pAbstract“in¾9terpretation“of“ëMsqDiffº,“with“and“without“using“ëMApplyETŽŽ¡Ž’öff„0³2ffŽŽ *š‰fföÌÌŽŽŽŽ X€ þÃþ‘íºâëOnº'th–ªcon¾9text“map.‘ÚxThis“is“then“applied“to“ëMalpha“ºwrappAÇedޤ ‘íºâup–NÍin“a“cš¾9hain“of“ëM(Fnc‘¹–...)“ºconstructions“whic˜h“supply“theŽ¡‘íºâremaining›TëOm–8ëP“ëOn“ëP“º1˜abstract˜v‘ÿ|ralue˜argumen¾9ts.Ž© ‘íºâThis–^seems“an“enormously“wš¾9asteful“w˜a˜y“to“sa˜y“what“amoun˜tsŽ¡‘íºâto:ޤÚ‘ûç¤ëMApplyET–¹–n“f“alphaŽ¡‘íºâºThat–##is,‘S”\extract“the“ëOnº'th“con¾9text“map“from“ëMf“ºand“apply“it“toޤ ‘íºâthe–M¯con¾9text“ëMalphaº".–ÅW‘ÿ:«ell,›[Æalmost.“In–M¯fact,˜ëMfº's“ëOnº'th“con¾9textŽ¡‘íºâmap–ïHexpšAÇects“to“b˜e“applied“not“directly“to“ëMalphaº,‘öäbut“to“theŽ¡‘íºâterm›œèëM(Fnc–¹–aj“...“(Fnc“am“alpha)“...)º.‘³+It˜loAÇoks˜at˜ rstŽ¡‘íºâlik•¾9e›‚~w“e˜need˜to˜include˜the˜abstract˜v‘ÿ|ralues˜ëMaj˜ºto˜ëMam˜ºin˜theŽ¡‘íºâëMApplyET‘=šºterm.‘–'F–ÿ:«ortunately“,‘ˆ that–=æis“a•¾9v“oidable:‘m”since‘=ætheyŽ¡‘íºâare–9vall“unitary‘ÿ:«,‘‚~wš¾9e“should“nev˜er“need“to“kno˜w“what“theyŽ¡‘íºâare.‘’÷Instead,‘†·wš¾9e–<Ösimply“record“in“the“ëMApplyET‘<Šºterm“ho˜wŽ¡‘íºâmanš¾9y–8Iof“these“\trailing"“argumen˜ts“there“are.‘…OWhen“theŽ¡‘íºâterm–ê%rewriter“ nally“gets“hold“of“ëMfº's“ëOnº'th“con¾9text“map,‘ZitŽ¡‘íºâuses–Tthis“n•¾9um“bAÇer–Tto“build“a“suitable“\dumm¾9y“term"ޤÚ‘ûç¤ëM(Fnc–¹–Error“...“(Fnc“Error“alpha)“...)Ž¡‘íºâºto–~üwhicš¾9h“it“applies“the“relev‘ÿ|ran˜t“con˜text“map.‘YhIn“e ect,‘™fw˜eޤ ‘íºâa•¾9v“oided–9storing“those“trailing“argumenš¾9ts,‘ïand“fak˜ed“themŽ¡‘íºâinstead,›F using–<^ëMError“ºterms,˜bAÇecause“wš¾9e“can“guaran˜tee“theyŽ¡‘íºâwill–žònevš¾9er“bAÇe“used.‘¹JF‘ÿ:«rom“this“it“follo˜ws“that“it“is“an“errorŽ¡‘íºâfor–TëMError“ºto“appAÇear“in“the“normal“form“of“an¾9y“term.ަ‘íºâUse–î°of“ëMApplyET‘îwºshrinks“man¾9y“terms“dramatically‘ÿ:«,‘%and“en-Ž¡‘íºâhances– Çthe“time“and“space“pAÇerformance“of“the“analyser.‘>ÉAsŽ¡‘íºâan–Texample,“Figure“1“shoš¾9ws“the“abstract“in˜terpretation“ofŽŸÚ‘ûç¤ëMsqDiff–¹–x“y“=“(x“+“y)“*“(x“-“y)ŽŽŽ þÃþ’õºâºwith–LÎand“without“using“ëMApplyETº.“Of“course,‘Z­when“the“de -ޤ ’õºânitions–Öof“ëM(+)º,›®vëM(-)“ºand“ëM(*)“ºare“substituted“in,˜bAÇoth“termsŽ¡’õºâreduce–'Zto“the“same“thing.‘RNote“that“ëM(CtxAp–¹–e1“e2)‘'ZºandŽ¡’õºâëM(AbsAp–¹–e1“e2)–õoºare“written“as“ëPfëMe1›¹–e2ëPg“ºand“ëPfëM*e1˜e2*ëPg“ºre-Ž¡’õºâspAÇectiv¾9ely‘ÿ:«.ŽŸ5’õºâ¹4.8Ž’ G·No•¹™rmal›LÎfo“rms˜and˜termination˜p“ropFfertiesŽ©m’õºâºShoš¾9wing–÷that“the“term“rewriting“system“alw˜a˜ys“terminates,Ž¡’õºâand–\`prošAÇduces“normal“forms,‘^is“imp˜ortan¾9t.‘ÞÉF‘ÿ:«or“a“system“withŽ¡’õºâas–B½man¾9y“rewrite“rules“and“complications“as“this,‘NproAÇducingŽ¡’õºâa– ªcorrectness“argumen¾9t“is“a“formidable“task.‘ùrW‘ÿ:«e“hopAÇe“toŽ¡’õºâinclude–›¦one“in“a“later“v¾9ersion“of“this“papšAÇer.‘¯fAlso“to“b˜eŽ¡’õºâincluded–Ewill“bAÇe“a“listing“of“the“rewrite“rules,‘‘ along“withŽ¡’õºâtheir–D€assošAÇciated“pro˜ofs“of“correctness.‘©ôThere“are“at“presen¾9tŽ¡’õºâin–Tthe“region“of“sixt¾9y“rewrite“rules.ŽŸ-’õºâ¹5Ž’”Firsti cation–LÎand“monomo¹™rphisationŽŸ†´’õºâ5.1Ž’ G·IntroFfductionަ’õºâºAlthough–¹· rst“order“functions“are“easily“handled“b¾9y“term-Ž¡’õºârewriting–­ based“ xpAÇoinš¾9ting,‘Áøhigher“order“recursiv˜e“functionsŽ¡’õºâgivš¾9e–Ttrouble,“as“t˜ypi ed“b˜y“foldr:Ž©ÐO’ç¤ëMfoldr–¹–f“a“[]‘Y„=“aŽ¡’ç¤foldr–¹–f“a“(x:xs)‘ s,=“f“x“(foldr“f“a“xs)ަ’õºâºNaiv•¾9ely›\Í xpAÇoin“ting˜this˜giv“es˜an˜series˜of˜appro“ximationsŽ¡’õºâin–­whicš¾9h“a“term“in˜v˜olving“functional“parameter“ëMf“ºis“appliedŽ¡’õºâev¾9er–J(more“times“to“an“initial“term.‘Ø·The“term“rewriter“cannotŽŽŽŽŽŽŸ’åä21ŽŽŒ‹% •ºâ ý? £ ý€‘íºâºshoš¾9w–Õ½that“t˜w˜o“appro˜ximations“are“the“same,‘Öso“a“ xpAÇoin˜tޤ ‘íºâis–-œapparenš¾9tly“nev˜er“reac˜hed.‘eHWhat's“really“going“on“is“thatŽ¡‘íºâthe–T xpšAÇoin¾9t“of“ëMfoldr“ºdep˜ends“on“the“ xp˜oin¾9t“of“ëMfº.Ž© ‘íºâThere– lare“only“t•¾9w“o› lw“a“ys˜round˜this.‘=¸The˜ rst˜is˜to˜iter-Ž¡‘íºâate–Ÿenough“times“to“bšAÇe“sure“that“the“ xp˜oin¾9t“is“certainlyŽ¡‘íºâreac•¾9hed.‘ЂW‘ÿ:«ork›QZb“y˜Nielson˜and˜Nielson˜[NN92Ž‘>]˜giv“es˜safeŽ¡‘íºâlo•¾9w“er–ö™bšAÇounds“on“the“n•¾9um“b˜er–ö™of“iterations“needed.‘À>Unfor-Ž¡‘íºâtunately‘ÿ:«,‘Wthe–¼expAÇense“of“doing“this“makš¾9es“it“unattractiv˜e.Ž¡‘íºâNote–Talso“that“this“approac¾9h“demands“monomorphisation.ަ‘íºâThe–M9second“solution“requires“us“to“supply“a“v‘ÿ|ralue“for“ëMf“ºbAÇe-Ž¡‘íºâfore–š% xpAÇoinš¾9ting“ëMfoldr,“ºso“that“w˜e“are,›»Yin“e ect,˜no“longerŽ¡‘íºâdealing–¿xwith“a“higher-order“function.‘ÜThere“are“n¾9umerousŽ¡‘íºâw•¾9a“ys–T¾to“do“this,‘d™some“rather“obscure“in“that“they“partiallyŽ¡‘íºâsubstitute–g?in“functional“parameters“as“part“of“the“ xpAÇoin¾9t-Ž¡‘íºâing–¶hproAÇcess“[ëN?Ž‘sº].‘ÿ­By“con¾9trast,‘­Anna“adopts“a“completelyŽ¡‘íºâstraigh•¾9tforw“ard›päapproac“h:‘Ó‘transform˜the˜source˜program.Ž¡‘íºâProgram–ñvtransformation“is“a“pAÇopular“sub‘ƒŽject,‘(~and“v‘ÿ|rariousŽ¡‘íºâpap•AÇers›—¶describ“e˜higher-order˜function˜remo•¾9v‘ÿ|ral˜(also˜kno“wnŽ¡‘íºâas–М rsti cation“or“spAÇecialisation)“[CD91Ž‘þä]‘¡8[NelŽ‘ žº].‘ˆThe“sc¾9hemeŽ¡‘íºâpresen•¾9ted›TbAÇelo“w˜is˜based˜on˜w“ork˜b“y˜George˜Nelan˜[NelŽ‘ žº].ަ‘íºâNot–Àall“functional“parameters“can“bAÇe“remo•¾9v“ed.‘ÇF‘ÿ:«or‘Àexam-Ž¡‘íºâple,‘õrecursivš¾9e–ífunctions“whic˜h“ha˜v˜e“accum˜ulating“functionalŽ¡‘íºâparameters–Iare“not“transformable,‘Æat“least“with“the“sc¾9hemeŽ¡‘íºâbAÇelo¾9w:Ž©:¢‘ûç¤ëMf–¹–g“x“=“if‘æXx“==“0Ž¡‘!´Tthen‘ s,g‘¹–1Ž¡‘!´Telse‘ s,x–¹–*“f“(\y“->“g“x“+“y)“(x-1)ަ‘íºâºW‘ÿ:«e– _justify“this“design“decision“on“the“basis“that“the“v‘ÿ|rastŽ¡‘íºâma‘ƒŽjorit¾9y–Yof“functions“that“pšAÇeople“really“write“can“b˜e“ rsti-Ž¡‘íºâ ed,‘T‰and–Gåthe“v‘ÿ|rast“ma‘ƒŽjoritš¾9y“of“the“rest“can“bAÇe“handled“b˜y“aŽ¡‘íºâsecondary–=§mec¾9hanism“outlined“in“section“6.4.‘•jIn“doing“thisŽ¡‘íºâwš¾9e–±Yimplicitly“appAÇeal“to“the“measuremen˜t-lead“approac˜h“toŽ¡‘íºâdesign–Ô¼discussed“in“the“in¾9troAÇduction.‘Z©W‘ÿ:«e“only“need“to“re-Ž¡‘íºâmo•¾9v“e–PÛfunctional“parameters“for“recursiv¾9e“functions,–_½but,“asŽ¡‘íºâbAÇecomes–’fclear,‘¬–this“means“ rstifying“non-recursiv¾9e“functionsŽ¡‘íºâtoAÇo.ŽŸæ‘íºâ¹5.2Ž‘G·Firsti cation–LÎb¹™y“examplesŽŸm‘íºâºF‘ÿ:«or–þcthe“momen¾9t,‘x§let's“use“ëMfoldr“ºas“a“running“example.Ž¡‘íºâGivš¾9en–Ta“use“of“ëMfoldrº,“lik˜eަ‘ûç¤ëMsum–¹–xs“=“foldr“(+)“0“xsަ‘íºâºwš¾9e–½can“unfold“functional“parameter“ëM(+)“ºand“iden˜tit˜y“ëM0“ºin˜toŽ¡‘íºâëMfoldrº,–Tgiving“a“new“function“ëMfoldrSpecº:ަ‘ûç¤ëMsum–¹–xs“=“foldrSpec“xsŽ¡¡‘ûç¤foldrSpec–¹–[]‘Y„=“0Ž¡‘ûç¤foldrSpec–¹–(x:xs)‘ s,=“x“+“foldr“(+)“0“xsަ‘íºâºAnd–noš¾9w,‘E%folding“the“b•AÇo“dy–of“ëMfoldrSpec“ºgiv˜es“what“w˜e“reallyŽ¡‘íºâw•¾9an“t:ަ‘ûç¤ëMsum–¹–xs“=“foldrSpec“xsŽ¡¡‘ûç¤foldrSpec–¹–[]‘Y„=“0Ž¡‘ûç¤foldrSpec–¹–(x:xs)‘ s,=“x“+“foldrSpec“xsަ‘íºâºThe–h5kš¾9ey“to“success“here“is“the“ease“with“whic˜h“that“lastŽ¡‘íºâfold–4wš¾9as“done.‘xÈIn“general,‘;Îfolding“is“a“tric˜ky“business,‘;ÎwithŽŽŽ ý€’õºâno–4`guaranš¾9tee“of“termination.‘y“Ho˜w˜ev˜er,‘|"b˜y“restricting“theޤ ’õºâfunctions–s‘wš¾9e“deal“with,‘‹ w˜e“can“guaran˜tee“to“mak˜e“the“foldŽ¡’õºâstep–¶ˆterminating,‘ÞÔand“trivial“to“carry“out.‘ The“restrictionŽ¡’õºâis–ÒPthat“the“function“mš¾9ust“pass“along“all“parameters“whic˜hŽ¡’õºâw•¾9e›¹w“an“t˜to˜sp•AÇecialise˜in˜the˜same˜p“osition˜in˜recursiv¾9e˜callsŽ¡’õºâas–ythey“appAÇeared“in“the“argumen¾9ts.‘+ßF‘ÿ:«or“example,‘Âin“ëMfoldrº,Ž¡’õºâbAÇoth–TëMa“ºand“ëMf“ºsatisfy“this.ŽŸ ’õºâIn–³fact,‘Ÿ:wš¾9e“only“w˜an˜t“to“substitute“in“functional“parameters.Ž¡’õºâSo–Tthe“transformation“of“ëMsum“ºis“really:Ž©ÐO’ç¤ëMsum–¹–xs“=“foldrSpec“0“xsŽ¡¡’ç¤foldrSpec–¹–a“[]‘Y„=“aŽ¡’ç¤foldrSpec–¹–a“(x:xs)‘ s,=“x“+“foldrSpec“a“xsަ’õºâºA‘ºlittle–ûterminology‘ÿ:«.‘ƨThe“function“or“recursiv¾9e“group“of“func-Ž¡’õºâtions–¯3-“for“example,‘àëMfoldr“º-“for“whic¾9h“functional“parametersŽ¡’õºâare–Ý·bAÇeing“remo•¾9v“ed–Ý·is“called“the“ëNtarget‘LÂgroupº.‘ æAnd“a“func-Ž¡’õºâtion–Tcon¾9taining“a“call“to“a“target“group“is“called“a“ëNsourceº.ŽŸ ’õºâThe–Oxrestriction“on“v‘ÿ|ralid“targets“seems“to“bAÇe“this:‘·the“func-Ž¡’õºâtion–Ímš¾9ust“pass“along“all“functional“parameters“unc˜hanged“inŽ¡’õºâall–~recursivš¾9e“calls.‘´ïGeneralising“this“to“deal“with“m˜utuallyŽ¡’õºârecursiv¾9e–ÃRtargets“requires“the“notion“of“a“ëNconstan´Ct‘Uargu-Ž¡’õºâmen´Ct‘Œßsetº.‘¨Calling–ga“recursiv¾9e“group“in“general“causes“callsŽ¡’õºâwithin–'the“group,‘œand“a“constanš¾9t“argumen˜t“set“gathers“to-Ž¡’õºâgether–&margumenš¾9ts“whic˜h“are“guaran˜teed“to“ha˜v˜e“the“sameŽ¡’õºâv‘ÿ|ralue–Tfor“evš¾9ery“sub-call.‘pF‘ÿ:«or“example,“giv˜enަ’ç¤ëMf–¹–x“y“z‘ s,=“f“y“y“z“+“g“z“xŽ¡’ç¤g–¹–a“b‘æX=“f“a“b“a“+“g“a“bަ’õºâºa–æÔlittle“thoughš¾9t“sho˜ws“ëMfº's“third“argumen˜t“and“ëMgº's“ rst“argu-Ž¡’õºâmenš¾9t–•sare“alw˜a˜ys“the“same,‘µ{giving“a“constan˜t“argumen˜t“setŽ¡’õºâwritten–g ëM{f.3,‘¹–g.1}º.‘–A‘fögroup“can“ha•¾9v“e–g more“than“one“set,Ž¡’õºâas–Tthe“folloš¾9wing“trivial“example“sho˜ws:ަ’ç¤ëMf–¹–x“y‘ s,=“g“x“yŽ¡’ç¤g–¹–a“b‘ s,=“f“a“bަ’õºâºConstan•¾9t›mïargumen“t˜sets˜can˜bAÇe˜computed˜using˜a˜simpleŽ¡’õºâabstract–Ë>in¾9terpretation“describšAÇed“b˜elo¾9w.‘¾What“is“imp˜ortan¾9tŽ¡’õºâhere– Iis“that“for“a“recursiv¾9e“target“group“to“bšAÇe“sp˜ecialisable,Ž¡’õºâall–ñbfunctional“parameters“in“the“group“mš¾9ust“bAÇe“constan˜t“ar-Ž¡’õºâgumenš¾9ts.‘ýCertain–µ‹other“constrain˜ts“also“apply–ÿ:«.‘ýW“e‘µ‹returnŽ¡’õºâto–Tthese“later.ŽŸ ’õºâThe–Tfolloš¾9wing“example“breaks“our“nice“sc˜heme:ަ’ç¤ëMmap–¹–f“[]‘Y„=“[]Ž¡’ç¤map–¹–f“(x:xs)‘ s,=“f“x“:“map“f“xsŽ¡¡’ç¤addN–¹–n“xs“=“map“(+“n)“xsަ’õºâºF‘ÿ:«olding–Tand“unfolding“as“abAÇo•¾9v“e‘Tgiv“esަ’ç¤ëMaddN–¹–n“xs“=“mapSpec“xsŽ¡¡’ç¤mapSpec–¹–[]‘Y„=“[]Ž¡’ç¤mapSpec–¹–(x:xs)‘ s,=“(x+n)“:“mapSpec“xsަ’õºâºwhic¾9h–Û†is“clearly“wrong“bAÇecause“ëMn“ºis“unde ned“in“ëMmapSpecº.Ž¡’õºâWhat–?jwš¾9e“need“to“do“is“pass“along“all“free“lam˜b•AÇda-b“oundŽ¡’õºâv›ÿ|rariables–Ѹin“the“spAÇecialising“v˜alue“ëM(+‘¹–n)“ºas“new“parameters,Ž¡’õºâin–Ta“stš¾9yle“reminiscen˜t“of“lam˜bAÇda-lifting:ŽŽŽŽŽŸ’åä22ŽŽŒ‹8— •ºâ ý? £ ý€‘ûç¤ëMaddN–¹–n“xs“=“mapSpec“n“xsޤ ¡‘ûç¤mapSpec–¹–n“[]‘Y„=“[]Ž¡‘ûç¤mapSpec–¹–n“(x:xs)‘ s,=“(x+n)“:“mapSpec“n“xsŽ©å‘íºâºNevš¾9ertheless–PØthis“still“allo˜ws“us“to“get“our“knic˜k˜ers“in“a“t˜wist.Ž¡‘íºâIn–d%the“folloš¾9wing“(admittedly“con˜triv˜ed)“example,‘·Ùw˜e“ma˜yŽ¡‘íºâselect–Teither“ëMinc“ºor“ëMg“ºas“a“source“to“transform“ rst:ަ‘ûç¤ëMapply–¹–f“x‘ s,=“f“xŽ¡‘ûç¤g–¹–a“b‘Y„=“apply“a“bŽ¡¡‘ûç¤inc–¹–y‘Y„=“g“(+“1)“yަ‘íºâºDoing–Tg“ rst“giv¾9es:ަ‘ûç¤ëMapplySpec–¹–x‘ s,=“a“xŽ¡‘ûç¤g–¹–a“b‘%̰=“applySpec“bŽ¡¡‘ûç¤inc–¹–y‘%̰=“g“(+“1)“yަ‘íºâºNo•¾9w›mÅw“e˜need˜to˜in“tro•AÇduce˜free˜v‘ÿ|rariables˜of˜the˜sp“ecialisingŽ¡‘íºâv‘ÿ|ralue–TëMa“ºas“a“new“parameter“to“ëMapplySpecº:ަ‘ûç¤ëMapplySpec–¹–a“x‘ s,=“a“xŽ¡‘ûç¤g–¹–a“b‘/?Ü=“applySpec“a“bŽ¡¡‘ûç¤inc–¹–y‘/?Ü=“g“(+“1)“yަ‘íºâºWhereupšAÇon–uit“should“b˜e“eminenš¾9tly“clear“that“w˜e'v˜e“ac˜hiev˜edŽ¡‘íºâexactly–Ànothing!‘…µOur“mistakš¾9e“w˜as“to“select“a“source“forŽ¡‘íºâwhic¾9h–çúthe“spAÇecialising“v›ÿ|ralue“had“function-v˜alued“free“v˜ari-Ž¡‘íºâables,‘˜ since–}åpassing“them“as“new“parameters“to“ëMapplySpecŽ¡‘íºâºmeans–œõëMapplySpec“ºis“still“a“higher-order“function.‘ôPThe“moralŽ¡‘íºâis–bTclear:‘¶qonly“transform“sources“for“whicš¾9h“the“free“lam˜bAÇda-Ž¡‘íºâbšAÇound–Òrv‘ÿ|rariables“of“the“sp˜ecialising“v‘ÿ|ralue“are“not“higher-Ž¡‘íºâorder.‘ÅA‘¿šsecond–¿Æobš¾9vious“constrain˜t“on“source“calls“is“thatŽ¡‘íºâthe–¿call“should“bAÇe“sucien¾9tly“applied“for“all“function-v‘ÿ|raluedŽ¡‘íºâparameters–Tto“bAÇe“visible.Ž© ‘íºâIn–5ïwhat“follo•¾9ws,‘bžw“e–5ïassume“that“naming“issues“are“dealt“withŽ¡‘íºâcorrectly‘ÿ:«.‘T=In–'îparticular,‘,”the“free“v‘ÿ|rariables“in“an“spAÇecialisingŽ¡‘íºâv‘ÿ|ralue–Îneed“to“bšAÇe“renamed“b˜efore“they“can“b˜e“safely“insertedŽ¡‘íºâas–Tnew“parameters“of“the“spAÇecialised“target.ަ‘íºâThe–²4algorithm“bšAÇelo¾9w“requires“the“program“to“b˜e“strati edŽ¡‘íºâinš¾9to–øminimal“m˜utually“recursiv˜e“groups,‘;áand“topAÇologicallyŽ¡‘íºâsorted.‘% W‘ÿ:«e–2adopt“the“usual“con•¾9v“en“tion–2that“the“programŽ¡‘íºâis–bIwritten“top-to-bAÇottom,‘u†with“anš¾9y“giv˜en“function“referringŽ¡‘íºâonly–‘oto“its“oš¾9wn“group,‘«Ðif“recursiv˜e,‘«Ðand“groups“abAÇo˜v˜e“it.‘ðyTheŽ¡‘íºârošAÇot–Texpression“is“righ¾9t“at“the“b˜ottom.ަ‘íºâSpAÇecialisation–(of“target“groups“ma¾9y“result“in“some“groupsŽ¡‘íºâbšAÇecoming–•Ðunreac¾9hable“from“ëMmainº.‘ãThese“groups“should“b˜eŽ¡‘íºâremo•¾9v“ed.‘í4A‘°more–°@dicult“problem“is“ho¾9w“to“insert“a“newŽ¡‘íºâgroup,‘ûÍresulting–š‚from“spAÇecialisation“of“an“existing“group,Ž¡‘íºâinš¾9to– –the“program“so“as“to“main˜tain“depAÇendancy‘ÿ:«.‘ÿ7It“turnsŽ¡‘íºâout– ðthat“t•¾9w“o› ðdi eren“t˜bAÇeha“viours˜are˜pAÇossible.‘?EIn˜the˜usualŽ¡‘íºâcase,–Tthe“new“group“\splits"“a•¾9w“a“y–Tfrom“the“source“group:ŽŸå‘ûç¤ëMletrec‘æXmap–¹–f“[]‘Y„=“[]Ž¡‘+'€map–¹–f“(x:xs)‘ s,=“f“x“:“map“f“xsŽ¡‘ûç¤in‘¹–letŽ¡‘+'€square–¹–x‘Y„=“x“*“xŽ¡‘ûç¤in‘¹–letŽ¡‘+'€squareList–¹–xs“=“map“square“xsŽ¡‘ûç¤in‘¹–...ŽŽŽ ý€’õºâºSince–L®the“spAÇecialised“target“ëMmapSpec“ºrefers“to“ëMsquareº,‘š…w¾9eޤ ’õºâmš¾9ust–‡place“it“after“ëMsquareº.‘sKT‘ÿ:«aking“this“argumen˜t“to“itsŽ¡’õºâconclusion–üEshoš¾9ws“w˜e“should“place“an˜y“\splitting"“group“im-Ž¡’õºâmediately–TbAÇefore“the“source“group:Ž©ÐO’ç¤ëMlet‘!square–¹–x‘%̰=“x“*“xŽ¡’ç¤in‘¹–letrecŽ¡’3'€mapSpec–¹–[]‘Y„=“[]Ž¡’3'€mapSpec–¹–(x:xs)‘ s,=“square“x“:Ž¡’ˆ4 mapSpec‘¹–xsŽ¡’ç¤in‘¹–letŽ¡’3'€squarelist–¹–xs‘,Â=“mapSpec“xsŽ¡’ç¤in‘¹–...ަ’õºâºSources–Tgiving“rise“to“\joining"“spAÇecialisations“are“un¾9usual:ަ’ç¤ëMletrec‘æXmap–¹–f“[]‘Y„=“[]Ž¡’3'€map–¹–f“(x:xs)‘ s,=“f“x“:“map“f“xsŽ¡’ç¤in‘¹–letrecŽ¡’3'€squareList‘¹–xsŽ¡’ATB=–¹–map“(head.squareList.unit)“xsŽ¡’ç¤in‘¹–...ަ’õºâºHere,›~ the–X8de nitions“of“ëM(.)º,˜ëMhead“ºand“ëMunit“ºare“unimpAÇortan¾9t.Ž¡’õºâBecause–ºthe“spAÇecialising“v‘ÿ|ralue“ëM(head.squareList.unit)Ž¡’õºâºrefers–z¶to“the“source“group“from“whic¾9h“it“originates,‘”the“re-Ž¡’õºâsulting–âáspAÇecialisation“of“ëMmap“ºwill“also“refer“to“ëMsquareListº,Ž¡’õºâand–âKthat“in“turn“means“the“spšAÇecialisation“should“b˜e“mergedŽ¡’õºâin¾9to–Tthe“source“group:ަ’ç¤ëMletrecŽ¡’fsquareList–¹–xs‘,Â=“mapSpec“xsŽ¡’fmapSpec–¹–[]‘Y„=“[]Ž¡’fmapSpec–¹–(x:xs)‘ s,=“(head.squareList.unit)“x“:Ž¡’g òmapSpec‘¹–xsŽ¡’ç¤in‘¹–...ަ’õºâºSince–{·only“recursivš¾9e“source“groups“can“refer“to“themselv˜es,Ž¡’õºâsp•AÇecialisations›Bcorresp“onding˜to˜sources˜in˜non-recursiv¾9eŽ¡’õºâgroups–Tnevš¾9er“exhibit“this“\joining"“bAÇeha˜viour.ŽŸ5’õºâ¹5.3Ž’ G·An‘LÎalgo¹™rithmŽŸm’õºâºThe–PùprošAÇcedure“b˜elo¾9w“is“rep˜eated“un¾9til“no“more“v‘ÿ|ralid“(source,Ž¡’õºâtarget)–Ò—pairs“can“bAÇe“found.‘T9As“shoš¾9wn“b˜y“Nelan“[NelŽ‘ žº],‘ètheŽ¡’õºâorder–)in“whicš¾9h“these“pairs“are“selected“mak˜es“no“di erence.Ž¡’õºâUn¾9used––Õtargets“should“bšAÇe“deleted,‘°"but“again“it“do˜esn't“mak¾9eŽ¡’õºâanš¾9y–Tdi erence“when.‘pAs“a“running“example,“w˜e“tak˜e:ަ’ÿ.ëMletrecŽ¡’ ZÐmap1–¹–f“g“(x:y:xys)‘ s,=“f“x“:“g“y“:“map2“g“f“xysŽ¡’ ZÐmap1–¹–f“g“_‘/?Ü=“[]Ž¡¡’ ZÐmap2–¹–g“f“(x:y:xys)‘ s,=“g“x“:“f“y“:“map1“f“g“xysŽ¡’ ZÐmap2–¹–g“f“_‘/?Ü=“[]Ž¡’ÿ.in‘¹–letŽ¡’ ZÐaddmul–¹–p“q“xs‘!=“map1“(+“p)“(*“q)“xsŽŸÐO’‰º1.ŽŽŽ’ :âFind–&´a“v›ÿ|ralid“target“group,‘k and“a“v˜alid“source“groupŽ¡’ :âwhic¾9h–Trefers“to“the“target“group.ŽŸÌÍ’g¤ëMTarget–¹–group‘,Â=“{map1,“map2}Ž¡’g¤Source–¹–group‘,Â=“{addmul},“refers“to“map1ŽŽŽŽŽŸ’åäº23ŽŽŒ‹Rè •ºâ ý? £ ý€‘ø‰º2.ŽŽŽ‘:âIf–‡dthe“target“group“is“recursivš¾9e,‘£çcompute“its“constan˜tޤ ‘:âargumenš¾9t–½Ðsets“(see“section“5.4).‘ãIn“realit˜y‘ÿ:«,‘çîthis“com-Ž¡‘:âputation–É$has“to“bšAÇe“p˜erformed“at“step“(1).‘ 7áIf“non-Ž¡‘:ârecursiv•¾9e,‘¿$man“ufacture–iûa“\fak¾9e"“singleton“set“listingŽ¡‘:âall–Thigher-order“parameters“as“constan¾9t.Ž©ª_‘g¤ëMConst–¹–arg“sets‘ s,=“{“{map1.1,“map2.2},Ž¡‘pç\{map1.2,–¹–map2.1}“}ަ‘ø‰º3.ŽŽŽ‘:âIn•¾9v“en“t–Aa“new“set“of“names“for“the“spAÇecialised“targetŽ¡‘:âgroup.ަ‘g¤ëMNew–¹–names‘ s,=“{map1Spec,“map2Spec}ަ‘ø‰º4.ŽŽŽ‘:âDetermine,‘çfrom–Ûlthe“constanš¾9t“argumen˜t“set,‘çwhic˜h“ar-Ž¡‘:âgumen¾9ts–¿Yin“the“source“call“site“are“the“spAÇecialising“v‘ÿ|ral-Ž¡‘:âues.‘²Extract–G8their“free“lam¾9b•AÇda-b“ound–G8v‘ÿ|rariables“andŽ¡‘:ârename.ަ‘g¤ëMOriginal:Ž¡‘!:specialising–¹–values“=“{(+“p),“(*“q)}Ž¡‘!:free–¹–variables‘Y„=“{p,“q}Ž¡¡‘g¤Renamed:Ž¡‘!:specialising–¹–values“=“{(+“pnew),“(*“qnew)}Ž¡‘!:free–¹–variables‘Y„=“{pnew,“qnew}ަ‘ø‰º5.ŽŽŽ‘:âRebuild–­½the“source“call“b¾9y“deleting“the“spAÇecialisationŽ¡‘:âv›ÿ|ralues,‘Åninserting–±tfree“v˜ariables“as“new“parameters,‘ÅnandŽ¡‘:âc¾9hanging–À+the“called“function“to“its“new“name,‘êáas“de-Ž¡‘:âtermined–Tin“step“(3).ަ‘g¤ëMRebuilt–¹–source“call‘ s,=“map1Spec“p“q“xsަ‘ø‰º6.ŽŽŽ‘:âBuild–2vthe“spAÇecialised“target“group,‘_Östarting“with“a“cop¾9yŽ¡‘:âof–$šthe“original“target“group.‘JAF‘ÿ:«or“eacš¾9h“recursiv˜e“callŽ¡‘:âinside–Táthe“group,‘dÄmoAÇdify“that“call“in“a“similar“w•¾9a“y‘TátoŽ¡‘:âhoš¾9w–Tthe“source“call“w˜as“moAÇdi ed“in“step“(5).ަ‘:âëMRebuilt–¹–target“group:Ž¡¡‘g¤map1Spec–¹–pnew“qnew“(x:y:xys)Ž¡‘ ”f=–¹–(x“+“pnew)“:“(y“*“qnew)“:Ž¡‘gt0map2Spec–¹–pnew“qnew“restŽ¡‘g¤map1Spec–¹–pnew“qnew“_Ž¡‘ ”f=‘¹–[]Ž¡¡‘g¤map2Spec–¹–pnew“qnew“(x:y:xys)Ž¡‘ ”f=–¹–(x“*“qnew)“:“(y“+“pnew)“:Ž¡‘gt0map1Spec–¹–pnew“qnew“restŽ¡‘g¤map2Spec–¹–pnew“qnew“_Ž¡‘ ”f=‘¹–[]ަ‘ø‰º7.ŽŽŽ‘:âDetermine–Zgwhether“the“spAÇecialised“target“group“shouldŽ¡‘:âsplit–»or“join,‘¦b¾9y“ nding“out“whether“the“spAÇecialisationŽ¡‘:âv‘ÿ|ralues–“fconš¾9tained“an˜y“reference“to“the“source“group.Ž¡‘:âAugmen¾9t–Tprogram“appropriately‘ÿ:«.ަ‘g¤ëMSpecialisation–¹–vals“{(+“p),“(*“q)}“don'tŽ¡‘g¤refer–¹–to“{addmul},“so“new“group“splits.ŽŸ­â‘íºâºA‘qùv‘ÿ|ralid–rnon-recursivš¾9e“target“group“m˜ust“consist“of“a“singleŽ¡‘íºâhigher–HØorder“function.‘¶ûA‘HÊv‘ÿ|ralid“recursiv¾9e“target“group“satis-Ž¡‘íºâ es–Tall“the“follo¾9wing:ŽŽŽ ý€’äëPŽŽŽ’ :âºAll–Ú–functions“in“the“group“ha•¾9v“e–Ú–at“least“one“functionalޤ ’ :âparameter.Ž©8’äëPŽŽŽ’ :âºEacš¾9h–¤lfunctional“parameter“in“the“group“is“a“mem˜bAÇerŽ¡’ :âof–s“exactly“one“of“the“group's“constanš¾9t“argumen˜t“sets.Ž¡’ :âThis–|implies“that“all“inš¾9tra-group“calls“m˜ust“bAÇe“su-Ž¡’ :âcienš¾9tly–Tapplied“to“expAÇose“all“functional“argumen˜ts.ަ’äëPŽŽŽ’ :âºEac•¾9h›¦âconstan“t˜argumen“t˜set˜m“ust˜men“tion˜exactly˜oneŽ¡’ :âargumenš¾9t–¤Çfor“eac˜h“function“in“the“group.‘ÊÊThis“disal-Ž¡’ :âloš¾9ws–'Úcertain“con˜triv˜ed“pathological“cases“whic˜h“w˜ouldŽ¡’ :âotherwise–Tseriously“complicate“the“algorithm.ޤšW’õºâA–Tv‘ÿ|ralid“source“call“site“satis es“the“follo¾9wing:Ž¡’äëPŽŽŽ’ :âºThe–Tsite“is“a“call“to“a“v‘ÿ|ralid“target“group.ަ’äëPŽŽŽ’ :âºThe–Bpapplication“mš¾9ust“ha˜v˜e“sucien˜t“argumen˜ts“to“sup-ޤ ’ :âply–Tall“higher“order“(spAÇecialisable)“argumen¾9ts.ަ’äëPŽŽŽ’ :âºF‘ÿ:«or–Û7eacš¾9h“spAÇecialisable“argumen˜t,‘Œ¯none“of“the“freeŽ¡’ :âlamš¾9b•AÇda-b“ound–&v‘ÿ|rariables“ma˜y“bAÇe,‘jNor“con˜tain,‘jNa“func-Ž¡’ :âtion‘Tspace.Ž©šW’õºâAlthough–/it“lošAÇoks“easy“on“pap˜er,‘uqimplemen¾9ting“this“algo-Ž¡’õºârithm–s3is“tricš¾9ky–ÿ:«.‘6 T“aking–s3in˜to“accoun˜t“the“mec˜hanisms“forŽ¡’õºâdetecting–ëbconstanš¾9t“argumen˜ts“and“main˜taining“t˜ypAÇe“anno-Ž¡’õºâtations,‘Íthe–èèHaskš¾9ell“implemen˜tation“approac˜hes“1500“linesŽ¡’õºâof‘TcoAÇde.ŽŸ*£’õºâ¹5.4Ž’ G·Computing–LÎconstant“a¹™rgument“setsŽŸm’õºâºA‘õ¦simple–õ®abstract“inš¾9terpretation“is“used.‘ãEac˜h“function“callŽ¡’õºâin–kÏthe“group“is“abstracted“to“expAÇose“the“parameters“it“passesŽ¡’õºâalong:ަ’ç¤ëMf–¹–x“y“z‘ s,=“f“y“y“z“+“g“z“xŽ¡’ç¤g–¹–a“b‘æX=“f“a“b“a“+“g“a“bަ’õºâºPhrased–Tabstractly‘ÿ:«,“this“bAÇecomes:ަ’ç¤ëMf:–¹–calls“f“[#2,“#2,“#3]Ž¡’fcalls–¹–g“[#3,“#1]Ž¡¡’ç¤g:–¹–calls“f“[#1,“#2,“#1]Ž¡’fcalls–¹–g“[#1,“#2]ަ’õºâºNo•¾9w›è;w“e˜iterate˜to˜a˜ xed˜pAÇoin“t,‘ñ@gathering˜a˜complete˜set˜ofŽ¡’õºâthe–‡opAÇossible“v‘ÿ|ralues“of“eacš¾9h“argumen˜t.‘í$There“is“a“list“for“eac˜hŽ¡’õºâfunction,‘£ƒand–‡eacš¾9h“list“con˜tains“a“set“of“pAÇossible“v‘ÿ|ralues“forŽ¡’õºâeac•¾9h›Targumen“t.‘pInitially‘ÿ:«,˜eac“h˜argumen“t˜can˜only˜bAÇe˜itself:ަ’ç¤ëMF0–¹–=“[“{f.1},“{f.2},“{f.3}“]Ž¡’ç¤G0–¹–=“[“{g.1},“{g.2}“]ަ’õºâºA•¾9t›å¹eac“h˜iteration,‘ï?new˜appro“ximations˜are˜computed˜b“y˜us-Ž¡’õºâing–EÉthe“abstract“v¾9ersions“of“functions“to“lošAÇok“up“p˜ossibleŽ¡’õºâargumenš¾9t–\sets“in“the“existing“appro˜ximation.‘ð¥Also,‘m¿the“ex-Ž¡’õºâisting–Tappro¾9ximation“is“merged“in“wholesale:ަ’ç¤ëMF1–¹–=“F0“U“[“{f.2},“{f.2},“{f.3}“]Ž¡’)´TU–¹–[“{g.1},“{g.2},“{g.1}“]Ž¡’f=–¹–[“{f.1,“f.2,“g.1},“{f.2,“g.2},“{f.3,“g.1}“]Ž¡¡’ç¤G1–¹–=“G0“U“[“{f.3},“{f.1}“]ŽŽŽŽŽŸ’åäº24ŽŽŒ‹i •ºâ ý? £ ý€‘!´TëMU–¹–[“{g.1},“{g.2}“]ޤ ‘ f=–¹–[“{f.3,“g.1},“{f.1,“g.2}“]Ž¡¡‘ûç¤F2–¹–=“F1“U“[“{f.2,“g.2},“{f.2,“g.2},“{f.3,“g.1}“]Ž¡‘+'€[–¹–{f.3,“g.1},“{f.1,“g.2},“{f.3,“g.1}“]Ž¡‘ f=–¹–[“{f.1,“f.2,“f.3,“g.1,“g.2},Ž¡‘ú¾{f.1,–¹–f.2,“g.2},“{f.3,“g.1}“]Ž¡¡‘ûç¤G2–¹–=“G1“U“[“{f.3,“g.1},“{f.1,“f.2,“g.1}“]Ž¡‘!´TU–¹–[“{f.3,“g.1},“{f.1,“g.2}“]Ž¡‘ f=–¹–[“{f.3,“g.1},“{f.1,“f.2,“g.1,“g.2}“]Ž©Y‘íºâºEv•¾9en“tually–g“b“->“b)“->“b“->“[a]“->“bަ‘íºâºGiv¾9en–[)Lthe“usualŽ¡‘íºâHask¾9ell–!de nition“of“ëM(++)›¹–::“[c]˜->˜[c]˜->˜[c]º,‘dŸw¾9e“canŽ¡‘íºâde neŽŽŽ ý€’ç¤ëMconcat–¹–=“foldr“(++)“[]ޤÐO’õºâºwhic¾9h–TspAÇecialises“to:Ž¡’ç¤ëMfoldrSpec–¹–a“[]‘Y„=“aޤ ’ç¤foldrSpec–¹–a“(x:xs)‘ s,=“x“++“foldrSpec“a“xsŽ¡¡’ç¤concat–¹–=“foldrSpec“[]ŽŸÐO’õºâºMerely–X†adding“and“deleting“argumenš¾9t“t˜ypAÇes“giv˜es“ëMfoldrSpecŽ¡’õºâºan–n`apparenš¾9t“t˜ypAÇe“ëMb–¹–->“[a]“->“bº,‘„¢whic˜h–n`is“toAÇo“gen-Ž¡’õºâeral.‘ !W‘ÿ:«e–»äneed“to“unify“the“t¾9ypšAÇe“of“sp˜ecialising“v‘ÿ|ralueŽ¡’õºâëM(++)º,‘ÑëM[c]–¹–->“[c]“->“[c]–Þ½ºwith“the“t¾9ypAÇe“of“the“func-Ž¡’õºâtional–ã­parameter“it“replaces,›×BëMa–¹–->“b“->“bº,˜and‘ã­applyŽ¡’õºâthe–¡Eresulting“substitution“ëM{a–¹–->“[c],“b“->“[c]}–¡Eºto“theŽ¡’õºâannotations–ò”on“ëMfoldrSpecº.‘´0This“giv¾9es“ëMfoldrSpec‘¹–::Ž¡’õºâ[c]–¹–->“[[c]]“->“[c]º,–Tas“required.Ž© ’õºâSuc•¾9h›Œ+tric“k“ery˜should˜not˜come˜as˜a˜complete˜surprise.‘€öAf-Ž¡’õºâter–ŸÁall,‘Â\the“Milner-Hindley“t¾9ypAÇe“rules“for“an“application“ofŽ¡’õºâëMf–¹–::“(T1“->“T2)–-!ºto“ëMa–¹–::“T3–-!ºrequire“uni cation“of“ëMT1“ºwithŽ¡’õºâëMT3º.‘pThat's–Te ectiv¾9ely“what“is“going“on“here.ަ’õºâThe–]Àneed“to“preservš¾9e“t˜ypAÇe“annotations“is“a“ma‘ƒŽjor“n˜uisanceŽ¡’õºâfrom–û°the“implemenš¾9tation“viewp•AÇoin˜t,‘5Gb“ecause–û°more“time“isŽ¡’õºâspAÇenš¾9t–gqin“ xing“up“t˜ypAÇes“than“doing“the“transformationŽ¡’õºâpropAÇer.‘àŸW›ÿ:«ork–aâto“impro•¾9v“e–aâeciency“is“a“priorit¾9y˜.‘àŸThe“sc¾9hemeŽ¡’õºâdescrib•AÇed›hab“o•¾9v“e˜is˜a˜ rst˜implemen“tation˜in˜whic“h˜correct-Ž¡’õºâness–Twš¾9as“more“impAÇortan˜t“than“eciency‘ÿ:«.Ž©5’õºâ¹5.6Ž’ G·Monomo¹™rphisationŽŸm’õºâºBy–Ýcomparison“with“ rsti cation,‘«\monomorphisation“is“sim-Ž¡’õºâple.›;÷Monomorphisation–Öis“a“t•¾9w“o-phase–ÖproAÇcess.˜The“ rstŽ¡’õºâpass–Jfconducts“what“amounš¾9ts“to“a“depth- rst“searc˜h“fromŽ¡’õºâëMmain–d©ºto“disco•¾9v“er–d©all“required“instances.‘ nThe“second“passŽ¡’õºâclones–Á×coAÇde,‘,÷c¾9hanges“function“names“accordingly“and“re-Ž¡’õºâstores–TdepAÇendancy“order.ަ’õºâ¹5.6.1Ž’úíCollecting–LÎthe“instancesŽŸm’õºâºI‘õÓam–ö indebted“to“Mark“Jones“for“suggesting“the“follo¾9wingŽ¡’õºâalgorithm.‘GYW‘ÿ:«e–x÷carry“a“set“ëMinstances“ºto“accum¾9ulate“theŽ¡’õºâev•¾9en“tual–g|result,‘¼and“a“stacš¾9k“ëMtoVisit“ºrecording“places“w˜eŽ¡’õºâneed–ÒLto“visit.‘Elemen¾9ts“of“ëMinstances“ºand“ëMtoVisit“ºare“pairsŽ¡’õºâof–”z(function“name,‘ôCt¾9ypšAÇe“expression)“sp˜ecifying“a“particu-Ž¡’õºâlar–C—instance“of“a“function.‘§8The“tš¾9ypAÇe“expressions“are“alw˜a˜ysŽ¡’õºâmonomorphic.ŽŸ ’õºâSince–B ëMmain“ºmaš¾9y“bAÇe“of“an˜y“t˜ypAÇe,‘Í6w˜e“trivially“monomor-Ž¡’õºâphise–£zit“bš¾9y“substituting“an˜y“t˜ypAÇe“v‘ÿ|rariables“with“ëMIntº.‘ÆáThisŽ¡’õºâgiv¾9es–ªa“single“initial“v‘ÿ|ralue“for“ëMtoVisitº,‘!with“ëMinstances“ºini-Ž¡’õºâtially–H bAÇeing“empt¾9y‘ÿ:«.‘´The“ nal“v‘ÿ|ralue“of“ëMinstances“ºis“thenŽ¡’õºâëMsearch(instances,‘¹–toVisit)º,‘Twhere:ŽŸÐO’õºâëMsearch(instances,‘¹–toVisit)Ž¡’ç¤=–¹–if‘æX[toVisit“is“empty]Ž¡’ ZÐthen‘ s,instancesŽ¡’ ZÐelseŽ¡’ ZÐlet‘,Ânext–¹–=“head“toVisitŽ¡’ ZÐin–æXif“next–¹–`elem`“instancesŽ¡’F Ø[We've–¹–already“been“here]Ž¡’ ZÐthen‘ s,search(instances,–¹–tail“toVisit)Ž¡’ ZÐelse‘ s,[Get–¹–the“function“specified“by“next.Ž¡’.mêFind–¹–out“what“instances“of“otherŽŽŽŽŽŸ’åäº25ŽŽŒ‹~ •ºâ ý? £ ý€‘&mêëMfunctions–¹–are“called.‘ s,Add“theseޤ ‘&mêinstances–¹–to“(tail“toVisit)“givingŽ¡‘&mêtoVisitAug,–¹–and“then“do]Ž¡‘&mêsearch({next}–¹–U“instances,“toVisitAug)ޤzÁ‘íºâºF‘ÿ:«or–Texample,“giv¾9enŽ¡‘ûç¤ëMid–¹–x‘ s,=“xޤ ‘ûç¤f–¹–x‘,Â=“id“xŽ¡‘ûç¤main‘ s,=–¹–id“42“+“ord“(f“'c')ޤzÁ‘íºâºthe–Talgorithm“runs“through“these“states:Ž¡‘ fëMinstances‘YÆ"toVisitޤ ‘íºâ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Ž¡‘íºâ{}‘zÙ<[(main,‘¹–Int)]Ž¡¡‘íºâ{(main,–¹–Int)}‘FßÊ[(id,‘,ÂInt“->“Int),Ž¡‘vÀà(f,‘æXChar–¹–->“Char)]Ž¡¡‘íºâ{(main,–¹–Int),‘FßÊ[(f,‘æXChar“->“Char)]Ž¡‘òtx(id,‘,ÂInt–¹–->“Int)}Ž¡¡‘íºâ{(main,–¹–Int),‘FßÊ[(id,‘,ÂChar“->“Char)]Ž¡‘òtx(id,‘,ÂInt–¹–->“Int),Ž¡‘òtx(f,‘æXChar–¹–->“Char)}Ž¡¡‘íºâ{(main,‘¹–Int),‘FßÊ[]Ž¡‘òtx(id,‘,ÂInt–¹–->“Int),Ž¡‘òtx(id,‘,ÂChar–¹–->“Char),Ž¡‘òtx(f,‘æXChar–¹–->“Char)}ŽŸzÁ‘íºâºThis–™givš¾9es“t˜w˜o“instances“for“ëMidº.‘ÜBecause“the“abstract“in˜ter-Ž¡‘íºâpretation–´Œof“t¾9ypšAÇes“maps“b˜oth“ëMInt“ºand“ëMChar“ºto“the“t•¾9w“o‘´Œp˜oin“tŽ¡‘íºâdomain,‘¥only–Ó.one“of“those“instances“is“needed“for“analysisŽ¡‘íºâpurpAÇoses.‘ú In–_9general,‘±²wš¾9e“can“exploit“the“fact“that“man˜yŽ¡‘íºâdi eren•¾9t›@Rt“ypAÇes˜are˜assigned˜the˜same˜domain˜to˜reduce˜theŽ¡‘íºâprogram–•±expansion“caused“b¾9y“monomorphisation.‘†F‘ÿ:«ar“andŽ¡‘íºâa•¾9w“a“y–èŒthe“easiest“w•¾9a“y–èŒto“do“this“is“to“transform“the“t¾9ypAÇe“an-Ž¡‘íºânotations–ñnto“domain“annotations“bAÇefore“monomorphisation,Ž¡‘íºâusing–ùýthe“results“of“section“2.2.5.‘ST¾9ypAÇe“v‘ÿ|rariables“are“simplyŽ¡‘íºâreplaced–Tb¾9y“domain“v‘ÿ|rariables.ŽŸòë‘íºâ¹5.6.2Ž‘ úíCloning‘LÎcoFfdeŽŸm‘íºâºThis–¨èis“fairly“trivial.‘×+Eac¾9h“function“is“duplicated“once“pAÇerŽ¡‘íºâinstance,‘ܶwith–´Öappropriate“new“names.‘úõThe“function“b•AÇo“d-Ž¡‘íºâies›#\ha•¾9v“e˜their˜call˜sites˜moAÇdi ed˜to˜refer˜to˜appropriatelyŽ¡‘íºânamed–_2instances“in“previous“groups,›qªand“this“one,˜if“recur-Ž¡‘íºâsivš¾9e.‘\Then–Ðthe“b•AÇo“dies–Ðha˜v˜e“the“t˜ypAÇe“v‘ÿ|rariables“in“their“anno-Ž¡‘íºâtations–çãsubstituted“appropriately“for“eacš¾9h“di eren˜t“instanceŽ¡‘íºârequired.‘¶eThe–ûen¾9tire“program“can“bšAÇe“pro˜cessed“in“a“singleŽ¡‘íºâtop-to-bAÇottom‘Tpass.Ž© ‘íºâThe–ŠËonly“slighš¾9tly“tric˜ky“problem“is“rebuilding“recursiv˜eŽ¡‘íºâgroups–”0so“as“to“mainš¾9tain“depAÇendancy–ÿ:«.‘™F“or‘”0non-recursiv˜eŽ¡‘íºâclones,›/this–Ã…is“easy‘ÿ:«,˜but“bAÇecause“of“the“existance“of“cer-Ž¡‘íºâtain›2Äcon•¾9triv“ed˜recursiv“e˜functions,‘: main“taining˜depAÇendancyŽ¡‘íºâin–ó«the“recursivš¾9e“case“can“bAÇe“complicated.‘·vW‘ÿ:«e“a˜v˜oid“theseŽ¡‘íºâproblems–"dbš¾9y“lumping“all“the“clones“arising“from“a“recursiv˜eŽ¡‘íºâfunction–ÿ‹group“in¾9to“a“single“ëMletrecº,‘:and“passing“the“pro-Ž¡‘íºâgram–Ta“third“time“though“the“depAÇendancy“analyser.ަ‘íºâDespite–8hthese“complications,‘,the“monomorphiser“is“ex-Ž¡‘íºâtremely–aÞquicš¾9k“and“doAÇes“not“pro˜v˜e“a“signi can˜t“limitationŽ¡‘íºâon‘TpAÇerformance.ŽŽŽ ý€’õºâ¹6Ž’”DiscussionŽŸ†´’õºâºThis–ÙÎsection“draš¾9ws“together“the“detailed“tec˜hnical“threadsޤ ’õºâexpAÇounded–‡in“the“previous“three“sections,‘š“bš¾9y“presen˜tingŽ¡’õºâsome–äkpšAÇerformance“results,‘1and“lo˜oking“at“related“and“fur-Ž¡’õºâther–Èxwš¾9ork.‘5ÜBut“w˜e“bAÇegin“b˜y“lošAÇoking“at“some“p˜erformanceŽ¡’õºâissues.ŽŸtŠ’õºâ¹6.1Ž’ G·Putting–LÎit“all“togetherŽŸm’õºâºThro¾9wing–°realistically“sized“programs“at“the“analyser“re-Ž¡’õºâvš¾9ealed–½psome“pAÇerformance“problems“whic˜h“w˜ere“traced“toŽ¡’õºâniceties–Xüin“the“inš¾9terface“bAÇet˜w˜een“the“abstract“in˜terpreter“andŽ¡’õºâthe–Tterm“rewriter.Ž© ’õºâP¾9erformance–òrproblems“appAÇear“when“the“term“rewriting“sys-Ž¡’õºâtem–u,is“fed“a“giganš¾9tic“term“to“simplify–ÿ:«.‘;ùUsually“,‘"suc˜h‘u,termsŽ¡’õºâreduce–-œto“something“quite“trivial.‘eHIt“is“impAÇortan¾9t“to“realiseŽ¡’õºâthat–}0the“abstract“in¾9terpreter“will“generate“absolutely“enor-Ž¡’õºâmous–úUterms,‘3–espAÇecially“from“source“text“whic¾9h“has“deeplyŽ¡’õºânested–BÊfunction“calls“or“deeply“nested“ëMcase“ºexpressions,‘læbAÇothŽ¡’õºâof–Ëwhic¾9h“are“quite“common.‘>÷F‘ÿ:«or“example,‘ù the“bigger“pro-Ž¡’õºâgrams–2menš¾9tioned“in“section“6.2“generated“terms“whic˜h,‘_êwhenŽ¡’õºâprett•¾9y-prin“ted–#in“the“stš¾9yle“used“in“this“papAÇer,‘&„co˜v˜ered“liter-Ž¡’õºâally–Ttens“of“A4“pages.ަ’õºâAnalysis–²¾of“a“program“proAÇceeds“as“follo¾9ws.‘ô­First,‘Úthe“pro-Ž¡’õºâgram–L•is“passed“in“its“en•¾9tiret“y–L•through“the“abstract“in¾9ter-Ž¡’õºâpreter,‘0generating–Ä«a“correspAÇonding“collection“of“recursiv¾9eŽ¡’õºâequations–\õ(or“terms).‘óTThese“equations“are“h¾9ugely“redun-Ž¡’õºâdan¾9t–`Ðand“are“simpli ed“individually‘ÿ:«,‘³®without“reference“toŽ¡’õºâeacš¾9h–“nother.‘–¾Finally‘ÿ:«,‘òôthe“ xpAÇoin˜ting“system“tra˜v˜els“alongŽ¡’õºâthe–_úgroups“of“equations,‘²£accumš¾9ulating“an“en˜vironmen˜t“ofŽ¡’õºâ\solv•¾9ed"›˜Ìequations.‘¦×A‘˜ªsolv“ed˜equation˜is˜self-con“tained:‘#_itŽ¡’õºâdoAÇes–2ònot“refer“to“the“abstract“inš¾9terpretation“of“an˜y“otherŽ¡’õºâfunction.‘ëÌSolving–ƒgnon-recursiv¾9e“equations“is“a“simple“matterŽ¡’õºâof–Ê\substituting“in“the“abstract“in¾9terpretations“of“other“func-Ž¡’õºâtions,›7and–Ösimplifying.‘,öF‘ÿ:«or“recursiv¾9e“functions,˜this“stage“isŽ¡’õºâfollo•¾9w“ed›Tb“y˜ xpAÇoin“ting.ަ’õºâWhat–Ðreally“ruins“pšAÇerformance“is“not“ xp˜oin¾9ting,‘C.but“theŽ¡’õºâinitial–úsimpli cation“of“terms“whic¾9h“emerge“from“the“ab-Ž¡’õºâstract–èeinš¾9terpreter.‘•¤This“problem“w˜as“largely“alleviated“b˜yŽ¡’õºâgiving–wªthe“abstract“inš¾9terpreter“a“little“more“in˜telligence,‘?inŽ¡’õºâthe–Tform“of:ŽŸît’äëPŽŽŽ’ :âºThe›#žt¾9yp•AÇe-sp“eci c˜ëMAbsVal˜ºrewrites˜describ“ed˜in˜sec-Ž¡’ :âtion‘T4.6.ŽŸBF’äëPŽŽŽ’ :âºA‘ëknoš¾9wledge–€Iof“k˜ey“ëMContext“ºrewrite“rules.‘]PIn“par-Ž¡’ :âticular,‘~9the–6 rules“for“ëMcase“ºstatemen¾9ts“generate“largeŽ¡’ :âexpressions›xin•¾9v“olving˜ëMCMeetº,–"ëMCJoinº,“ëMStop1˜ºand˜ëMStop2º.Ž¡’ :âA‘Ôhandful–Ôyof“rules“emš¾9b•AÇo“dying–Ôysimple“facts“suc˜h“asŽ¡’ :âëMCMeet–¹–[...“Stop2“...]“==“Stop2–Tºw¾9ere“added.ŽŸ ¡#’ :âBet•¾9w“een–Yêthem,‘gthe“sizes“of“terms“generated“w¾9ere“some-Ž¡’ :âtimes–Ù‚cut“bš¾9y“t˜w˜o“orders“of“magnitude,‘Jand“pAÇerfor-Ž¡’ :âmance–Twš¾9as“m˜uc˜h“impro˜v˜ed.ŽŸîu’õºâA‘m†second–m±pAÇerformance“problem“w¾9as“traced“to“the“initial“sim-Ž¡’õºâpli cation–M²of“terms“emerging“from“the“abstract“in¾9terpreter.Ž¡’õºâThese–=¬terms“are“simpli ed“without“reference“to“eac¾9h“other.Ž¡’õºâIt–ïÚturns“out“to“bšAÇe“b˜etter“to“simplify“a“term“only“whenŽ¡’õºâw•¾9e›ñxkno“w˜the˜solv“ed˜v‘ÿ|ralues˜of˜the˜other˜terms˜it˜refers˜to,Ž¡’õºâbAÇecause–V”knoš¾9wing“these“v‘ÿ|ralues“mak˜es“the“ nal“term“m˜uc˜hŽ¡’õºâsmaller.‘Ñ€In–§e ect,‘Ëpthis“is“ac•¾9hiev“ed–§simply“b¾9y“omitting“thisŽ¡’õºâsimpli cation–?Wpass“altogether.‘šzF‘ÿ:«or“at“least“one“input,‘IØanal-Ž¡’õºâysis–Ttime“wš¾9as“cut“b˜y“a“factor“of“ v˜e.ŽŽŽŽŽŸ’åä26ŽŽŒ‹˜d •ºâ ý? £ þ ¦dŸ¸lΑíºâŸ´S4‰fföÌ̤ÿþ•ÌÍ ‹Ùš„’Ù˜ffŸ­32‘àŸÐŒÍ‰ffÍF§¡“Ÿ„ ff‘fg„ ff‘6˜ý„ ffŽ‘X¦GŸ„ ff‘fg„ ffŽ‘z3ñºF‘ÿ:«or–Ta“complete“run‘ZwŸ„ ff‘fg„ ffŽ’ýœIAnalysis‘Tonly‘˜VŸ„ ff‘fg„ ffŽ’W5áCompiling–Twith“ëMghc-0.10‘ }Ÿ„ ff‘fg„ ffŽŽ¤fh‘Z¦G„ffr `ŽŽŸ™˜“¤„ ff‘fg„ ff‘33ŸüÿþºProgram‘H³¡„ ffŽ‘>2–Lines‘33Ÿ„ ff‘fg„ ffŽ‘kg&Time‘33Ÿ„ ffŽ’ÚClaim‘33Ÿ„ ffŽ’Ê|´Space‘33Ÿ„ ff‘fg„ ffŽ’ù‘ŸTime‘33Ÿ„ ffŽ’++SClaim‘33Ÿ„ ff‘fg„ ffŽ’[FwTime‘33Ÿ„ ffŽ’{%äanalysis–Ttime“as“%‘33Ÿ„ ff‘fg„ ffŽŽ¡‰ffÍF§Ÿÿþ“Ÿ„ ff‘fg„ ff‘6˜ý„ ffŽ‘X¦GŸ„ ff‘fg„ ffŽ’…¬úŸ„ ffŽ’º[Ÿ„ ffŽ’æÐÀŸ„ ff‘fg„ ffŽ’×sŸ„ ffŽ’H…˜Ÿ„ ff‘fg„ ffŽ’uŒKŸ„ ffŽ’ËF§Ÿ„ ff‘fg„ ffŽŽ¤ “¤„ ff‘fg„ ff‘33Ÿüÿþconcat‘0€¡„ ffŽ‘?ìëO<‘Tº10‘33Ÿ„ ff‘fg„ ffŽ‘iL©0.42‘Ts‘33Ÿ„ ffŽ’”†1.485‘TM‘33Ÿ„ ffŽ’É4´47.2‘Tk‘33Ÿ„ ff‘fg„ ffŽ’÷w"0.18‘Ts‘33Ÿ„ ffŽ’"±0.586‘TM‘33Ÿ„ ff‘fg„ ffŽ’Y+ú0.92‘Ts‘33Ÿ„ ffŽ’²Ò19‘T%‘33Ÿ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff‘33Ÿüÿþzip3‘ ô ¡„ ffŽ‘?ìëO<‘Tº10‘33Ÿ„ ff‘fg„ ffŽ‘iL©0.52‘Ts‘33Ÿ„ ffŽ’”†1.793‘TM‘33Ÿ„ ffŽ’É4´56.1‘Tk‘33Ÿ„ ff‘fg„ ffŽ’÷w"0.17‘Ts‘33Ÿ„ ffŽ’"±0.570‘TM‘33Ÿ„ ff‘fg„ ffŽ’Y+ú1.00‘Ts‘33Ÿ„ ffŽ’²Ò17‘T%‘33Ÿ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff‘33Ÿüÿþw¾9ang‘•Ó¡„ ffŽ‘E“385‘33Ÿ„ ff‘fg„ ffŽ‘d¬«23.62‘Ts‘33Ÿ„ ffŽ’æ‘85.396‘TM‘33Ÿ„ ffŽ’Ä”¶908.8‘Tk‘33Ÿ„ ff‘fg„ ffŽ’÷w"9.15‘Ts‘33Ÿ„ ffŽ’ 15.861‘TM‘33Ÿ„ ff‘fg„ ffŽ’T‹ü43.61‘Ts‘33Ÿ„ ffŽ’²Ò21‘T%‘33Ÿ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff›33Ÿüÿþw•¾9a“v“e4main˜¡„ ffŽ‘E“619‘33Ÿ„ ff‘fg„ ffŽ‘d¬«43.40‘Ts‘33Ÿ„ ffŽ’‹F“116.207‘TM‘33Ÿ„ ffŽ’¿ô¸2897.7‘Tk‘33Ÿ„ ff‘fg„ ffŽ’ò×$21.62‘Ts‘33Ÿ„ ffŽ’ 43.239‘TM‘33Ÿ„ ff‘fg„ ffŽ’Oëþ199.29‘Ts‘33Ÿ„ ffŽ’²Ò11‘T%‘33Ÿ„ ff‘fg„ ffŽŽ¡“¤„ ff‘fg„ ff‘33Ÿüÿþag2hs‘¼:¡„ ffŽ‘@ó1047‘33Ÿ„ ff‘fg„ ffŽ‘` ­208.95‘Ts‘33Ÿ„ ffŽ’‹F“275.245‘TM‘33Ÿ„ ffŽ’¿ô¸9653.8‘Tk‘33Ÿ„ ff‘fg„ ffŽ’î7&126.42‘Ts‘33Ÿ„ ffŽ’q 135.335‘TM‘33Ÿ„ ff‘fg„ ffŽ’Oëþ100.68‘Ts‘33Ÿ„ ffŽ’­hÔ126‘T%‘33Ÿ„ ff‘fg„ ffŽŽ¡“Ÿ„ ff‘fg„ ff‘6˜ý„ ffŽ‘X¦GŸ„ ff‘fg„ ffŽ’…¬úŸ„ ffŽ’º[Ÿ„ ffŽ’æÐÀŸ„ ff‘fg„ ffŽ’×sŸ„ ffŽ’H…˜Ÿ„ ff‘fg„ ffŽ’uŒKŸ„ ffŽ’ËF§Ÿ„ ff‘fg„ ffŽŽŸfh‰ffÍF§ŽŽŽŸEÌÌ’Ÿ¸/T‘ÿ:«able–T2:‘pSome“pAÇerformance“ gures“for“ëNAnnaŽŽŸ Ž’öff„’Ù˜ffŽŽ Œ@‰fföÌÌŽŽŽŽ öYœ þ%¦d‘íºâ¹6.2Ž‘G·Absolute–LÎpFferfo¹™rmance“resultsŽŸm‘íºâºFivš¾9e–ÿWtest“programs“w˜ere“used.‘ÚxThe“ rst“t˜w˜o,‘9×ëMconcat“ºandޤ ‘íºâëMzip3º,‘ZŠare–utterly“trivial“and“w¾9ere“included“as“comparisonŽ¡‘íºâagainst–Ûì gures“presen¾9ted“in“[Sew93Ž‘/].‘p7ëMwang“ºand“ëMwave4mainŽ¡‘íºâºare–‡Htakš¾9en“from“Pieter“Hartel's“bAÇenc˜hmark“suite“[HL92Ž‘÷l].‘íTheŽ¡‘íºâbiggest›²›one,–ÙíëMag2hsº,“is˜preproAÇcessor˜for˜a˜dialect˜of˜Hask¾9ellŽ¡‘íºâaugmen¾9ted–ˆðwith“attribute“grammar“[Joh87Ž‘Ä9]“facilities,‘¥Öwrit-Ž¡‘íºâten–Ãbš¾9y“Da˜vid“Rushall.‘ %ŸThe“analyser“w˜as“compiled“withŽ¡‘íºâChalmers–ÙîHask¾9ell-B‘Ù»0.999.4,‘ with“ ags“ëM-fpbu‘¹–-Oº,“and“runŽ¡‘íºâusing–èçan“eighš¾9t“megab˜yte“heap“for“all“except“ëMag2hsº,‘Ëwhic˜hŽ¡‘íºârequired–~¢a“sixteen“megab¾9yte“heap.‘XYA‘~‡generational“garbageŽ¡‘íºâcollector–W×wš¾9as“emplo˜y˜ed.‘ãøT‘ÿ:«ests“w˜ere“run“on“a“ligh˜tly“loadedŽ¡‘íºâSun–ˆ¨Sparc“10/31,‘¤Ëand“eacš¾9h“test“w˜as“pAÇerformed“at“least“threeŽ¡‘íºâtimes.‘pTimes–Tare“user“CPU“seconds.Ž© ‘íºâSimply–Ãmeasuring“o•¾9v“erall–Ãrun“times“is“not“particularly“help-Ž¡‘íºâful,‘mbAÇecause–[†wš¾9e“really“w˜an˜t“to“establish“ho˜w“expAÇensiv˜e“thisŽ¡‘íºâanalyser–Š¢wš¾9ould“bAÇe“if“emplo˜y˜ed“in“a“Hask˜ell“compiler.‘|ZItŽ¡‘íºâseems–v²reasonable“to“consider“the“\bšAÇorder"“b˜et•¾9w“een–v²the“fron¾9tŽ¡‘íºâend–”and“the“analyser“itself“as“the“pAÇoinš¾9t“where“the“t˜ypAÇe-Ž¡‘íºâc•¾9hec“k“er–ØÁprošAÇduces“a“t¾9yp˜e-annotated“Core“tree,–äÞsince,“at‘ØÁleastŽ¡‘íºâin–q±Glasgoš¾9w“Hask˜ell,‘ÈÈthe“compiler“proAÇduces“this“tree“an˜y-Ž¡‘íºâw•¾9a“y‘ÿ:«.‘€So›ƒw“e˜presen“t˜ gures˜not˜only˜for˜a˜complete˜run,‘butŽ¡‘íºâalso– §for“the“analysis“phase“propAÇer.‘6The“latter“category“co¾9v-Ž¡‘íºâers›Ç_ rsti cation,–Öömonomorphisation,“abstract˜in¾9terpretationŽ¡‘íºâand–¼ xpAÇoinš¾9ting,‘DÛall“of“whic˜h“are“legitimate“analysis“expAÇenses.ަ‘íºâT‘ÿ:«o–assess“whether“or“not“wš¾9e“are“approac˜hing“the“righ˜t“ball-Ž¡‘íºâpark,‘C§wš¾9e–;timed“Glasgo˜w“Hask˜ell“0.10“compiling“the“programsŽ¡‘íºâin¾9to–®*C,“and“compared“those“times“with“the“analysis“phaseŽ¡‘íºâtime–á^of“Anna.‘ The“compiler“options“w¾9ere“ëM-O2‘¹–-Cº.“CompilerŽ¡‘íºâsemispace–Œ¡sizes“wš¾9ere“3“megab˜ytes“for“the“small“t˜w˜o,‘ªsand“8Ž¡‘íºâmegabš¾9ytes–¸¡for“the“big“three:‘c this“turned“out“to“bAÇe“plen˜t˜y‘ÿ:«.Ž¡‘íºâThe–¢times“repAÇorted“for“Glasgoš¾9w“Hask˜ell“are“for“the“compilerŽ¡‘íºâpropAÇer,–£(that›†œis,“that˜part˜of˜the˜compiler˜whic¾9h˜is˜itself˜writ-Ž¡‘íºâten–fin“Haskš¾9ell,‘ëand“whic˜h“translates“the“output“of“the“Y‘ÿ:«accŽ¡‘íºâparser–Tin¾9to“C.ަ‘íºâT‘ÿ:«able–¿À2“presenš¾9ts“the“ gures.‘µThe“maxim˜um“residency“ g-Ž¡‘íºâures–½wš¾9ere“obtained“using“a“cop˜ying“collector“with“heap“sizesŽ¡‘íºâset–¯only“just“big“enough.‘êðThis“quan•¾9tit“y–¯is“omitted“for“theŽ¡‘íºâanalysis-only–° gures“bAÇecause“of“the“diculties“of“decidingŽ¡‘íºâon– Èho¾9w“to“divide“space“expšAÇenses“b˜et•¾9w“een– Èthe“fron¾9t“end“andŽ¡‘íºâthe–Tanalysis“phase.ަ‘íºâF‘ÿ:«or–¯{the“big“three,›Ötimes“are,˜v¾9ery“roughly‘ÿ:«,˜divided“equallyŽ¡‘íºâbAÇet•¾9w“een–âÿthe“fron¾9t“end“and“analysis“phases.‘ ©ëMag2hs“ºhas“a“rel-Ž¡‘íºâativ¾9ely–؈large“analysis“time“in“comparison“to“its“size.‘f ThisŽ¡‘íºâis–4bAÇecause“it“makš¾9es“considerable“use“of“lazy“pattern“matc˜h-Ž¡‘íºâing,‘FÆwhicš¾9h– °translates“to“a“large“quan˜tit˜y“of“complex“CoreŽŽŽ þ%¦d’õºâexpressions.‘ÓìThese–R}in“turn“generate“some“large,‘¡Çcomplexޤ ’õºâsets–(zof“equations“for“the“ xpAÇoinš¾9ter“to“solv˜e.‘UâA‘(3tec˜hniqueŽ¡’õºâmenš¾9tioned–9ìin“section“6.4“migh˜t“help“here.‘Š9F‘ÿ:«or“the“largerŽ¡’õºâproblems,›—¢space–x4consumption“is“of“concern.‘èMuc¾9h,˜if“not“theŽ¡’õºâma‘ƒŽjoritš¾9y‘ÿ:«,‘©@of–‹«the“space“used“is“related“to“fron˜t-end“proAÇcess-Ž¡’õºâing,‘›+and–€fit“seems“likš¾9ely“that“the“analysis“itself“is“relativ˜elyŽ¡’õºâcš¾9heap–Þon“space.‘¶F‘ÿ:«urther“in˜v˜estigation“with“a“heap“pro lerŽ¡’õºâis‘Tnecessary‘ÿ:«.Ž© ’õºâThe–±results“of“comparing“analysis“time“with“a“run“of“Glasgo¾9wŽ¡’õºâHaskš¾9ell–Ueon“the“same“program“are“in˜triguing.‘ÜvThe“tests“are“atŽ¡’õºâleast–øfair“in“the“sense“that“bAÇoth“Anna“and“the“Hask¾9ell“com-Ž¡’õºâpiler–Äare“written“in“Hask¾9ell,‘ {so“neither“has“an“unfair“adv‘ÿ|ran-Ž¡’õºâtage.‘ñàJust–•£bš¾9y“themselv˜es,‘¯-it“is“a“little“un˜usual“that“ëMghc“ºcom-Ž¡’õºâpiled–šÍëMag2hs“ºin“almost“half“the“time“it“toAÇok“for“ëMwave4mainº.Ž¡’õºâIt–’+maš¾9y“bAÇe“that“the“hea˜vy“use“of“n˜umeric“o˜v˜erloading“in“ëMwangŽ¡’õºâºand–еëMwave4main“ºhas“slo•¾9w“ed›еdo“wn˜ëMghc˜ºas˜it˜will˜ha“v“e˜hadŽ¡’õºâto–îûgenerate“and“optimise“large“quan¾9tities“of“dictionary“han-Ž¡’õºâdling–bdcoAÇde.‘àËëMag2hsº,›†.b¾9y“comparison,˜is“mostly“string“handling:Ž¡’õºâthere–ÜÌis“little“o•¾9v“erloading–ÜÌin“it.‘rÙAnna“has“a“naiv¾9e“view“ofŽ¡’õºâthe–ÐKHaskš¾9ell“n˜um˜bAÇers“{“it“only“kno˜ws“abAÇout“ëMIntº,‘ÿso“it“willŽ¡’õºânot›)ôha•¾9v“e˜seen˜an“y˜suc“h˜n“umeric˜o“v“erloading.‘ZQIn˜order˜toŽ¡’õºâmakš¾9e–¨Anna“accept“these“t˜w˜o“programs,‘Ëw˜e“had“to“strip“outŽ¡’õºâthe–‘äextensivš¾9e“t˜ypAÇe“signatures“whic˜h“had“bAÇeen“placed“thereŽ¡’õºâexpressely–vxto“eliminate“nš¾9umeric“o˜v˜erloading.‘?ÝThese“factorsŽ¡’õºâma•¾9y›8·w“ell˜ha“v“e˜conspired˜to˜giv“e˜Anna˜a˜remark‘ÿ|rably˜go•AÇo“d˜rel-Ž¡’õºâativ•¾9e›Š#sho“wing˜for˜ëMwang˜ºand˜ëMwave4mainº,‘§Walthough˜it˜is˜hardŽ¡’õºâto–ÂèbAÇelievš¾9e“they“accoun˜t“for“all“the“di erence“bAÇet˜w˜een“11%Ž¡’õºâ(ëMwave4mainº)–Tand“126%“(ëMag2hsº).ަ’õºâBecause–½ëMwang“ºand“ëMwave4main“ºare“mac¾9hine-generatedŽ¡’õºâHask¾9ell,‘LJthe–ALexpressions“in“them“are“reasonably“simple“andŽ¡’õºâsmall.‘†·By–8Ácomparison,‘Aœthe“desugared“v¾9ersion“of“ëMag2hs“ºcon-Ž¡’õºâtained–ušsome“v¾9ery“large“expressions“and“some“quite“compli-Ž¡’õºâcated–-±structured“t•¾9ypšAÇes.‘e†W‘ÿ:«atc“hing–-±the“b˜eha¾9viour“of“AnnaŽ¡’õºâon–Þ³this“example,‘é it“is“clear“that“the“ma‘ƒŽjorit¾9y“of“the“analysisŽ¡’õºâtime–Jïis“spšAÇen¾9t“ xp˜oin¾9ting“a“single“large“group“of“ab˜out“t•¾9w“en“t“yŽ¡’õºâfunctions–µÀwhicš¾9h“arose“from“the“extensiv˜e“use“of“lazy“patternŽ¡’õºâmatc¾9hing.‘~ÀIt–6seems“plausible“that“this“particular“group“didŽ¡’õºânot–œãcause“anš¾9y“similar“dicult˜y“to“ëMghcº,‘¾Çand“it“ma˜y“also“bAÇeŽ¡’õºâpšAÇossible–x£that“ëMghcº's“desugarer“did“a“b˜etter“job“than“Anna'sŽ¡’õºâin–qCtranslating“the“pattern“matc•¾9hing.‘0the‘qCdis-Ž¡’õºâparitš¾9y–çin“relativ˜e“analysis/compile“costs“bAÇet˜w˜een“ëMag2hs“ºandŽ¡’õºâthe–òÔother“t•¾9w“o–òÔbig“examples“is“a“wš¾9arning“that“w˜e“should“notŽ¡’õºâread–¡\toAÇo“m•¾9uc“h›¡\in“to˜these˜measuremen“ts˜bAÇey“ond˜the˜pAÇerhapsŽ¡’õºâheartening–ò]conclusion“that“wš¾9e“are“indeed“approac˜hing“theŽ¡’õºârigh¾9t–Tballpark“for“analyser“pAÇerformance.ŽŽŽŽŽŽŸ’åä27ŽŽŒ‹´† •ºâ ý? £ ý€‘íºâ¹6.3Ž‘G·Related‘LÎw•¹™o“rkŽŸm‘íºâºMycroft's–òoriginal“wš¾9ork“[Myc80Ž‘¸|]“on“applying“abstract“in˜ter-ޤ ‘íºâpretation–ûÍto“the“analysis“of“functional“programs“spark¾9ed“o Ž¡‘íºâin•¾9tense›[éw“ork˜on˜forw“ard˜analyses.‘Þ¢A‘[¹forw“ard˜strictness˜anal-Ž¡‘íºâysis–kktells“us“the“de nedness“of“a“function“application“giv¾9enŽ¡‘íºâthe–±¿de nedness“of“the“argumen¾9ts.‘û>Landmark“papAÇers“includeŽ¡‘íºâthe–*Burn-Hankin-Abramsky“wš¾9ork“[BHA85Ž‘¬b]“whic˜h“put“higherŽ¡‘íºâorder–„analysis“on“a“ rm“theoretical“foAÇoting,‘TPand“W‘ÿ:«adler'sŽ¡‘íºâpapAÇer–ÌÓ[W‘ÿ:«ad87Ž‘¿˜]“whicš¾9h“sho˜w˜ed“ho˜w“one“migh˜t“deal“sensiblyŽ¡‘íºâwith–.sum-of-prošAÇducts“t•¾9yp˜es.‘èýImplemen“tors–.made“m•¾9uc“h‘.ofŽ¡‘íºâ nding–¤ xpAÇoinš¾9ts“using“the“F‘ÿ:«ron˜tiers“algorithm,‘º¼massaging“itŽ¡‘íºâextensiv¾9ely–mèto“deal“with“higher“order“functions“[HH91Ž‘>],‘esum-Ž¡‘íºâof-pro•AÇducts›~#t¾9yp“es˜[Sew91Ž‘/]˜and˜p“olymorphism˜[Sew93Ž‘/].‘VÜDe-Ž¡‘íºâspite–ѽthis“and“other“tric•¾9k“ery–ѽ[HH92Ž‘>]“[Sew92Ž‘/],‘ßBfron¾9tiers“failedŽ¡‘íºâto–Âdeliv¾9er“usable“pAÇerformance“for“high-de nition“strictnessŽ¡‘íºâanalysis–päfor“an¾9ything“other“than“trivial“inputs,‘‘Èand“there“areŽ¡‘íºâgo•AÇo“d–¬õtheoretical“reasons“for“bAÇelieving“the“situation“cannotŽ¡‘íºâbAÇe‘Timpro•¾9v“ed.Ž© ‘íºâStarting–{at“around“the“same“time,‘™íanother“scš¾9hoAÇol“of“though˜tŽ¡‘íºâw•¾9as›þÐdev“eloping˜bac“kw“ards,–Qor˜pro‘ƒŽjection,“analyses.‘ïA‘þÊbac¾9k-Ž¡‘íºâwš¾9ards–·analysis“sho˜ws“ho˜w“the“seman˜tic“quan˜tit˜y“in“questionŽ¡‘íºâ-–Jphere,‘W·demand“for“ev‘ÿ|raluation“-“propagates“from“a“functionŽ¡‘íºâapplication–@to“the“individual“argumen¾9ts.‘Õ\Hughes“[Hug90Ž‘ó']“ar-Ž¡‘íºâgues–¼Ûthat“bac•¾9kw“ards–¼Ûanalyses“are“inherenš¾9tly“more“ecien˜tŽ¡‘íºâthan–U[forwš¾9ard“ones,‘e]bAÇecause“the“function“spaces“with“whic˜hŽ¡‘íºâthe–¯Àanalyses“deal“are“smaller“in“the“bac•¾9kw“ards‘¯Àcase.‘ú”Pro‘ƒŽjec-Ž¡‘íºâtion–êãanalysis“deals“easily“with“sum-of-prošAÇducts“t¾9yp˜es,‘ GandŽ¡‘íºâcaptures–ÔZcertain“propAÇerties,›Dsuc¾9h“as“head-strictness,˜thatŽ¡‘íºâseem–žto“elude“forw¾9ard“analyses.‘¶ˆA‘ãgo•AÇo“d–žreference“for“pro-Ž¡‘íºâjection–Þanalysis“is“[WH87Ž‘±].‘v¯Later“wš¾9ork“sho˜w˜ed“ho˜w“to“doŽ¡‘íºâmak¾9e–+únon- at“pro‘ƒŽjection“analysis“pAÇolymorphic“[HugŽ‘³+],‘q¤andŽ¡‘íºâa–Úñsuccessful“non- at,‘ WpAÇolymorphic“pro‘ƒŽjection“analyser“w¾9asŽ¡‘íºâbuilt–Tinš¾9to“Glasgo˜w“Hask˜ell“[KHL91Ž‘(Ô].ަ‘íºâDespite–ãÔthese“successes,‘tpro‘ƒŽjection“analyses“ha•¾9v“e–ãÔa“funda-Ž¡‘íºâmen•¾9tal› #inabilit“y˜to˜deal˜with˜higher˜order˜functions.‘÷ÞF‘ÿ:«ol-Ž¡‘íºâloš¾9wing–Ëœthe“lead“of“W‘ÿ:«ra˜y“[W‘ÿ:«ra85Ž‘:C],‘ù.Hughes“de ned“a“mixedŽ¡‘íºâanalysis–ô|whicš¾9h“w˜as“forw˜ards“for“the“higher“order“bits“andŽ¡‘íºâbac•¾9kw“ards–SŠfor“evš¾9erything“else“[Hug87Ž‘ó'].‘×Doing“this“giv˜es“anŽ¡‘íºâanalysis–r+whic¾9h“deals“with“higher-orderness“whilst“retainingŽ¡‘íºâthe–‡äinherenš¾9t“eciency“of“bac˜kw˜ard“analysis.‘íKRecen˜tly‘ÿ:«,‘¤.otherŽ¡‘íºâw•¾9ork“ers›ÌQha“v“e˜b•AÇegun˜to˜explore˜the˜relationship˜b“et•¾9w“een˜for-Ž¡‘íºâwš¾9ard–ÒÉand“bac˜kw˜ard“analysis“[Bur90Ž‘Žã]“[HL90Ž‘÷l]“[D˜W90Ž‘N].‘TÐTheŽ¡‘íºâanalysis–³ÁdescribšAÇed“in“this“pap˜er“is“a“mo˜di cation“of“Hughes'Ž¡‘íºâoriginal–Tmixed“analysis.ަ‘íºâMean•¾9while,‘=pAÇeople›xha“v“e˜b•AÇeen˜lo“oking˜at˜other˜w•¾9a“ys˜of˜solv-Ž¡‘íºâing–vÝrecursiv¾9e“domain“equations.‘A There“has“bAÇeen“a“discern-Ž¡‘íºâable–Jƒshift“to•¾9w“ards–Jƒterm“orienš¾9ted“approac˜hes.‘»üF‘ÿ:«erguson“andŽ¡‘íºâHughes–ö#dev¾9elopAÇed“\concrete“data“structures"“(CDSs)“[ëN?Ž‘sº]Ž¡‘íºâbased–7…on“Curien's“wš¾9ork“on“sequen˜tial“algorithms“[Cur86Ž‘¯õ].Ž¡‘íºâCDSs–‚Îdeal“with“higher-orderness“b¾9y“regarding“a“higher“or-Ž¡‘íºâder–#%function“as“conš¾9taining“a“CDS‘#!in˜terpreter“for“eac˜h“func-Ž¡‘íºâtional–®0parameter.‘çThis“is“really“a“disguised“w•¾9a“y–®0of“substi-Ž¡‘íºâtuting–‡in“functional“parameters“bšAÇefore“ xp˜oin¾9ting.‘ìÿWhetherŽ¡‘íºâor–not“CDSs“can“delivš¾9er“a“viable“ xpAÇoin˜ting“mec˜hanism“re-Ž¡‘íºâmains–þto“bAÇe“seen.‘îmEarly“implemenš¾9tations“hin˜ted“at“spaceŽ¡‘íºâproblems,‘€but–®Dthese“maš¾9y“no˜w“ha˜v˜e“bAÇeen“solv˜ed“[Hug93Ž‘ó'].Ž¡‘íºâCDSs–/·can“also“bAÇe“view¾9ed“as“a“higher-order“generalisationŽ¡‘íºâof–ÁÁthe“minimal“function“graph“sc¾9heme“originally“describAÇedŽ¡‘íºâb¾9y–E§Neil“Jones“[JM86Ž‘zú].‘­jMinimal“function“graphs“are“usedŽ¡‘íºâin–=Äthe“Semanš¾9tique“analyser“[KHL91Ž‘(Ô]“built“in˜to“Glasgo˜wŽ¡‘íºâHask¾9ell‘T[PHHP93Ž‘#µø].ަ‘íºâThe–ü“term“rewriting“based“ xpšAÇoin¾9ter“describ˜ed“here“w¾9as,ŽŽŽ ý€’õºâin–œÅpart,‘¾¡inspired“b¾9y“Charles“Consel's“strictness“analyser“inޤ ’õºâthe–G¿Y‘ÿ:«ale“Hask¾9ell“compiler“[Gro92Ž‘ÀP].‘³±Consel's“papAÇer“[Con91Ž‘±¼],Ž¡’õºâwhicš¾9h–Îseems“to“ha˜v˜e“passed“b˜y“almost“unnoticed,‘µdescribAÇedŽ¡’õºâa–7#successful,›–if“simple,˜strictness“analyser“solving“ xpAÇoin¾9tŽ¡’õºâequations–•Ybš¾9y“term“rewriting.‘œIn“view“of“ho˜w“w˜ell“this“andŽ¡’õºâConsel's–}ásystem“wš¾9ork,‘œ,it“is“pAÇerhaps“a“pit˜y“that“P˜eyton“JonesŽ¡’õºâet–;al“made“disparaging“remarks“abšAÇout“term-based“ xp˜oin¾9t-Ž¡’õºâing–Tin“their“seminal“fron¾9tiers“papAÇer“[PC87Ž‘9].ŽŸ5’õºâ¹6.4Ž’ G·F•¹™urther‘LÎw“o“rkŽŸm’õºâºAnna's–N¾pAÇerformance“is“encouraging.‘È­Nev¾9ertheless,‘there'sŽ¡’õºâstill–ê¿a“long“w•¾9a“y–ê¿to“go“bAÇefore“ev‘ÿ|raluation“transformer“infor-Ž¡’õºâmation–BÙcan“bšAÇe“generated“automatically“in“pro˜duction“com-Ž¡’õºâpilers.‘pThree›Ta•¾9v“en“ues˜of˜dev“elopmen“t˜need˜to˜b•AÇe˜p“ersued.ŽŸÐO’äëPŽŽŽ’ :âëNEnhancemenš´Ct–jeof“applicabilit˜y‘ÿÌ.‘È]ºAnna's–most“w¾9orry-Ž¡’ :âing–®alimitation“is“her“inabilit¾9y“to“deal“with“higher“orderŽ¡’ :âfunctions–Ûwhic¾9h“cannot“bšAÇe“ rsti ed.‘ôA‘½p˜ossible“partialŽ¡’ :âsolution–ÉMis“to“iterate“these“(or,›Ø‚more“precisely‘ÿ:«,˜just“theŽ¡’ :ânastš¾9y–Âwbits)“as“man˜y“times“as“is“necessary“to“guaran-Ž¡’ :âtee–GÔa“ xpAÇoinš¾9t.‘×ðThe“w˜ork“of“Nielson“and“Nielson“[NN92Ž‘>]Ž¡’ :âgivš¾9es–7ethe“magic“n˜um˜bAÇer“of“iterations“needed.‘ÒvF‘ÿ:«or“man˜yŽ¡’ :âcommon–’'forms,›ñ[this“n•¾9um“bAÇer–’'is“reasonably“lo¾9w,˜andŽ¡’ :âit–Zseems“reasonable“to“expAÇect“this“approac¾9h“to“yieldŽ¡’ :âw•¾9orth“while‘Tresults.Ž© ™š’ :âIt–·eis“also“necessary“to“remo•¾9v“e–·esome“of“the“excessiv¾9e“re-Ž¡’ :âstrictions–Jion“user-de ned“data“t¾9ypAÇes“discussed“in“sec-Ž¡’ :âtion–\ô2.2.6.‘óQThis“došAÇes“not“app˜ear“to“b˜e“particularlyŽ¡’ :âdicult.‘òKubiak–\Šet“al“[KHL91Ž‘(Ô]“managed“this“quiteŽ¡’ :âsuccessfully‘ÿ:«.ŽŸ34’äëPŽŽŽ’ :âëNEnhancemen´Ct–gof“pK¼erformance.‘÷ÙºThe–§Žre nemen¾9ts“ofŽ¡’ :âsection–=Œ6.1“ha•¾9v“e–=Œdone“a“lot“to“impro•¾9v“e–=Œthe“system'sŽ¡’ :âpAÇerformance.‘¡Nevš¾9ertheless,‘Œ˜some–A‹programs“w˜e“triedŽ¡’ :ârecen¾9tly–›Ö-“in“excess“of“a“thousand“lines“-“run“moreŽ¡’ :âsloš¾9wly–îÀthan“one“w˜ould“lik˜e.‘¨µIn˜v˜estigations“are“bAÇeingŽ¡’ :âmade.ަ’ :âFixpAÇoin¾9ting–L½large“groups“of“functions“could“conciev-Ž¡’ :âably–ðbAÇe“accelerated“b¾9y“reducing“the“group“to“a“\mini-Ž¡’ :âmal–Tform"“ rst.‘pF‘ÿ:«or“example,“giv¾9enŽ©ÌÍ’g¤ëMa–¹–=“...“a“...“b“...Ž¡’g¤b–¹–=“...“c“...Ž¡’g¤c–¹–=“...“c“...“d“...Ž¡’g¤d–¹–=“...“a“...ަ’ :âºwš¾9e–`®can“remo˜v˜e“ëMb“ºand“ëMd“ºb˜y“substituting“them“in˜to“ëMa“ºandŽ¡’ :âëMc– åºrespAÇectivš¾9ely‘ÿ:«.‘ This“halv˜es“the“n˜um˜bAÇer“of“functions“inŽ¡’ :âthe–ÿ2group“bšAÇeing“ xp˜oin¾9ted.‘Ú Once“the“solutions“to“ëMaŽ¡’ :âºand–ÆlëMc“ºha•¾9v“e–ÆlbAÇeen“generated,‘Ö4w¾9e“obtain“v‘ÿ|ralues“for“ëMb“ºandŽ¡’ :âëMd–Tºbš¾9y“straigh˜tforw˜ard“bac˜k-substitution.ŽŸ ™š’ :âNote–G that“this“tecš¾9hnique“ma˜y“bAÇe“used“in“an˜y“situa-Ž¡’ :âtion›¥¿in•¾9v“olving˜ xpAÇoin“ting˜m“utually˜recursiv“e˜groups˜ofŽ¡’ :âequations.‘µÆThe–Æidea“stems“from“an“analogy“with“theŽ¡’ :âGauss-Jordan–„¨methoAÇd“for“solving“sim¾9ultaneous“linearŽ¡’ :âequations.‘zíIn–4Óthis“case,‘<³a“recursiv¾9e“group“can“only“bAÇeŽ¡’ :âreduced–Ito“the“pAÇoinš¾9t“where“ev˜ery“equation“in“the“groupŽ¡’ :ârefers–öœdirectly“to“itself“{“no“further.‘ÀHAfter“that,‘.î x-Ž¡’ :âpAÇoinš¾9ting–x is“una˜v˜oidable.‘DWhether“or“not“this“rendersŽ¡’ :âa–ŸspšAÇeedup“dep˜ends“on“the“relativ¾9e“costs“of“substitution,Ž¡’ :âbacš¾9k–Tsubstitution“and“ xpAÇoin˜ting.ŽŽŽŽŽŸ’åä28ŽŽŒ‹ÜÑ •ºâ ý? £ ý€‘ûäëPŽŽŽ‘:âëNDealing–¦with“moK¼dulesº.‘ 5MoAÇdules–ÈZare“an“unmiti-ޤ ‘:âgated–†Çnš¾9uisance“for“man˜y“kinds“of“high“pAÇo˜w˜ered“seman-Ž¡‘:âtic–xManalyses“and“optimisations.‘E\In“particular,‘Ñ moAÇd-Ž¡‘:âules–Ñcause“big“diculties“for“an¾9y“kind“of“what“JohnŽ¡‘:âY›ÿ:«oung–(termed“\collecting“in¾9terpretations"“[Y˜ou89Ž‘-Ò].‘TÂAŽ¡‘:âcollecting–‘Tinš¾9terpretation“is“essen˜tially“a“global“anal-Ž¡‘:âysis.‘ vøMan¾9y–Þ,compile“time“optimisations“are“limitedŽ¡‘:âb¾9y–$the“moAÇdule“structure.‘IøF‘ÿ:«or“example,‘hMsome“of“theŽ¡‘:âmore–Äirecenš¾9t“sc˜hemes“for“compiling“o˜v˜erloading“ef-Ž¡‘:â cien¾9tly–[Jon93Ž‘Ä9]“[Aug93Ž‘ó']“require“global“analysis“forŽ¡‘:âfull–Ê=applicabilitš¾9y‘ÿ:«.‘ ;,The“pAÇoin˜t“of“all“this“is“that“theŽ¡‘:âmonomorphisation–+œand“ rsti cation“transformationsŽ¡‘:âused–Tin“Anna“also“require“a“global“view.ŽŸ Ûk‘:âThere–”"is“an“urgen¾9t“need“to“devise“sophisticated“com-Ž¡‘:âpilation–×wsystems“whicš¾9h“main˜tain“enough“in˜termoAÇduleŽ¡‘:âcommš¾9unication–?™to“mak˜e“global“analyses“pAÇossible.‘›?De-Ž¡‘:âv•¾9elopmen“t–»fof“sucš¾9h“a“framew˜ork“w˜ould“bAÇene t“not“onlyŽ¡‘:âstrictness–oªanalysis,‘†@but“man¾9y“aspAÇects“of“compile“timeŽ¡‘:âoptimisation.‘©¨Sucš¾9h–™¼a“compiler“migh˜t“w˜ork“b˜y“dump-Ž¡‘:âing–^øa“lot“of“information“inš¾9to“a“moAÇdule's“in˜terface“ le,Ž¡‘:âenough–A‚to“do“whatevš¾9er“analyses“w˜e“need.‘ úThis“w˜ouldŽ¡‘:âreally–©„just“bAÇe“an“extension“of“the“sc¾9hemes“used“al-Ž¡‘:âready–a in“the“Chalmers“and“Glasgoš¾9w“compilers,‘sûwhic˜hŽ¡‘:âdump–ù{function“aritš¾9y“and“rudimen˜tary“strictness“infor-Ž¡‘:âmation–¯inš¾9to“in˜terface“ les.‘µThe“question“is“not“re-Ž¡‘:âally–@ whether“wš¾9e“could“construct“suc˜h“a“system,‘ŠÓbutŽ¡‘:âwhether–ˆ¯the“quan•¾9tit“y–ˆ¯of“information“dumpAÇed“in¾9to“in-Ž¡‘:âterface–3ú les“could“bAÇe“limited“sucien¾9tly“to“render“theŽ¡‘:âsc¾9heme‘Tpractical.Ž©™µ‘íºâ¹Ackno¹™wledgementsŽŸ†´‘íºâºThanks–9Íto“Bill“Mitc¾9hell“for“advice“on“building“term“rewrit-Ž¡‘íºâing– ‚systems,‘ ¬and“to“Barney“Hilkš¾9en“for“an“in˜v‘ÿ|raluable“insigh˜tŽ¡‘íºâregarding–separate“compilation“systems.‘ê Mark“Jones“pro-Ž¡‘íºâvided–ñmanš¾9y“in˜teresting“commen˜ts“abAÇout“monomorphisationŽ¡‘íºâand–Oz rsti cation,‘^and“outlined“the“instance-collecting“algo-Ž¡‘íºârithm–߯of“Section“5.6.1.‘ ŽGeo rey“Burn“and“Denis“Ho•¾9w“e‘߯w“ereŽ¡‘íºâsucien•¾9tly›8Öbra“v“e˜to˜expAÇerimen“t˜with˜the˜implemen“tation,Ž¡‘íºâand–Tproš¾9vided“useful“feedbac˜k.ŽŸ ‘íºâDenis›Û³Ho•¾9w“e˜read˜an˜early˜draft˜in˜min“ute˜detail.‘ :His˜exten-Ž¡‘íºâsivš¾9e–³|and“sometimes“am˜usingŸü-=Õ2ŽŽ‘Þ#ºcommen˜ts“pro˜v˜ed“v˜ery“helpfulŽ¡‘íºâin–Tmaking“the“presen¾9tation“clearer.ަ‘íºâ¹ReferencesŽŸÅ‘íºâº[Aug87]ŽŽ‘fL.‘|Augustsson.‘ŠëRCompiling–J´Lš‡azy“F‘ÿJªunctional“L˜an-Ž¡‘fguages,‘l’Part‘f€IIº.‘h€PhD‘/¶thesis,‘6WChalmers‘/¼T‘ÿ:«eknisk‘ÿ|raŽ¡‘fH–û`ogsk¾9ola,›TG“otebAÇorg,˜Sw¾9eden,˜1987.Ž©¶Ö‘íºâ[Aug93]ŽŽ‘fLennart–¤êAugustsson.‘bImplemenš¾9ting“hask˜ell“o˜v˜er-Ž¡‘floading.‘-ðIn‘ÍëRPr•‡o“c“e“e“dings–AEof“the“F‘ÿJªunctional“Pr‡o-Ž¡‘fgr•‡amming›•`L“anguages˜and˜Computer˜AÃŽr“chite“ctur“eŽ¡‘fConfer•‡enc“e,›NRepAÇort“CSC/87/R3,‘SøUni-Ž¡‘fv•¾9ersit“y–ƒ\of“Glasgo•¾9w,‘ÞÝDepartmen“t–ƒ\of“ComputingŽ¡‘fScience,–TMarc¾9h“1987.ަ‘íºâ[Hug90]ŽŽ‘fJohn–ÞHughes.‘ jþCompile-time“analysis“of“func-Ž¡‘ftional–programs.‘ ¾In“Da¾9vid“A.“T‘ÿ:«urner,‘Úedi-Ž¡‘ftor,‘KFëRR•‡ese“ar“ch–f$T›ÿJªopics“in“F˜unctional“Pr•‡o“gr“ammingº.Ž¡‘fAddison-W›ÿ:«esley–AûPublishing“Compan¾9y˜,‘ #1990.Ž¡‘fF›ÿ:«rom–Јthe“1987“Y˜ear“of“Programming,‘ÞKUniv•¾9ersit“yŽ¡‘fof–TT›ÿ:«exas,“Austin,“T˜exas.ަ‘íºâ[Hug93]ŽŽ‘fJohn–7ÃHughes.‘€kPriv‘ÿ|rate“comm¾9unication“regardingŽ¡‘fcdss,‘T1993.ަ‘íºâ[JM86]ŽŽ‘fNeil–šD.“Jones“and“Alan“Mycroft.‘PÇData“ o¾9w“anal-Ž¡‘fysis–Ïof“applicativ¾9e“programs“using“minimal“func-Ž¡‘ftion–ô•graphs:‘ Abridged“v¾9ersion.‘ämIn“ëRUnknown,‘6)butŽ¡‘fde nitely–N