File: Template.hs

package info (click to toggle)
haskell-repa 3.4.1.5-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 304 kB
  • sloc: haskell: 3,135; makefile: 2
file content (98 lines) | stat: -rw-r--r-- 3,333 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{-# LANGUAGE TemplateHaskell, QuasiQuotes, ParallelListComp #-}

-- | Template
module Data.Array.Repa.Stencil.Template
        (stencil2)
where
import Data.Array.Repa.Index
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import qualified Data.List      as List

-- | QuasiQuoter for producing a static stencil defintion.
--
--   A definition like
--
--   @
--     [stencil2|  0 1 0
--                 1 0 1
--                 0 1 0 |]
--   @
--
--   Is converted to:
--
--   @
--     makeStencil2 (Z:.3:.3)
--        (\\ix -> case ix of
--                  Z :. -1 :.  0  -> Just 1
--                  Z :.  0 :. -1  -> Just 1
--                  Z :.  0 :.  1  -> Just 1
--                  Z :.  1 :.  0  -> Just 1
--                  _              -> Nothing)
--   @
--
stencil2 :: QuasiQuoter
stencil2 = QuasiQuoter
                { quoteExp      = parseStencil2
                , quotePat      = undefined
                , quoteType     = undefined
                , quoteDec      = undefined }


-- | Parse a stencil definition.
--   TODO: make this more robust.
parseStencil2 :: String -> Q Exp
parseStencil2 str
 = let
        -- Determine the extent of the stencil based on the layout.
        -- TODO: make this more robust. In particular, handle blank
        --       lines at the start of the definition.
        line1 : _       = lines str
        sizeX           = fromIntegral $ length $ lines str
        sizeY           = fromIntegral $ length $ words line1

        -- TODO: this probably doesn't work for stencils who's extents are even.
        minX            = negate (sizeX `div` 2)
        minY            = negate (sizeY `div` 2)
        maxX            = sizeX `div` 2
        maxY            = sizeY `div` 2

        -- List of coefficients for the stencil.
        coeffs          = (List.map read $ words str) :: [Integer]

   in   makeStencil2' sizeX sizeY
         $ filter (\(_, _, v) -> v /= 0)
         $ [ (fromIntegral y, fromIntegral x, fromIntegral v)
                | y     <- [minX, minX + (1 :: Integer) .. maxX]
                , x     <- [minY, minY + (1 :: Integer) .. maxY]
                | v     <- coeffs ]


makeStencil2'
        :: Integer -> Integer
        -> [(Integer, Integer, Integer)]
        -> Q Exp

makeStencil2' sizeX sizeY coeffs
 = do   ix'             <- newName "ix"
        z'              <- [p| Z |]
        coeffs'         <- newName "coeffs"

        let fnCoeffs
                = LamE  [VarP ix']
                $ CaseE (VarE (mkName "ix"))
                $   [ Match     (InfixP (InfixP z' (mkName ":.") (LitP (IntegerL oy)))
                                        (mkName ":.") (LitP (IntegerL ox)))
                                (NormalB $ ConE (mkName "Just") `AppE` LitE (IntegerL v))
                                [] | (oy, ox, v) <- coeffs ]
                    ++ [Match WildP
                                (NormalB $ ConE (mkName "Nothing")) []]

        return
         $ AppE (VarE (mkName "makeStencil2") 
                        `AppE` (LitE (IntegerL sizeX)) 
                        `AppE` (LitE (IntegerL sizeY)))
         $ LetE [ PragmaD (InlineP (mkName "coeffs") Inline FunLike (BeforePhase 0))
                , ValD    (VarP    coeffs')          (NormalB fnCoeffs) [] ]
                (VarE (mkName "coeffs"))