Links und Funktionen
Sprachumschaltung

Navigationspfad
Sie sind hier: Startseite / Lehre / SS 2018 / Programmierung und Modellierung / ProMo Material / Code 02.07.18


Inhaltsbereich

Code 02.07.18

1 Teil: Beispiel Par-Monade. 2 Teil: NFData und vollständiges Auswerten von Datenstrukturen.

Haskell source code icon parfib.hs — Haskell source code, 4 KB (4343 bytes)

Dateiinhalt

{- Beispiel Par-Monade

  Vorlesung "Programmierung und Modellierung"
  LMU München, Sommersemester 2018
  Steffen Jost

  1. Teil: Demo parallele Berechnung mit der Par-Monade

  2. Teil: NFData und Laziness/Striktheit

  --------------------------------------------------------------
  --  1.TEIL:
  --------------------------------------------------------------

  > stack install monad-par

  > stack ghc parfib.hs
  [1 of 1] Compiling Main             ( parfib.hs, parfib.o )
  Linking parfib ...

  > time ./parfib
  331160282

  real    0m22.978s
  user    0m22.884s
  sys     0m0.064s


  > stack ghc -- parfib.hs -fforce-recomp -threaded -rtsopts
  [1 of 1] Compiling Main             ( parfib.hs, parfib.o )
  Linking parfib ...
  > time ./parfib +RTS -N2
  331160282

  real    0m11.922s
  user    0m23.582s
  sys     0m0.072s

  Wir sehen:
  - die gesamte CPU-Berechnungszeit (gelistet unter "user") ist etwas gestiegen,
  - die real verstrichene Zeit (gelistet unter "real") ist jedoch fast halbiert worden,
    da wir zwei CPU-Kerne parallel eingesetzt haben!
-}

import Control.Monad.Par
import Control.DeepSeq

fib :: Integer -> Integer -- irgendeine aufwändige Berechnung
fib n | n < 2     = 1 
      | otherwise = fib (n-1) + fib (n-2)

main :: IO ()
main =
  let s = runPar $ do
          xref <- new               -- :: Par (IVar Integer)
          yref <- new               -- :: Par (IVar Integer)
          fork $ put xref $ fib 40  -- :: Par ()
          fork $ put yref $ fib 40  -- :: Par ()
          x <- get xref             -- :: Par Integer
          y <- get yref             -- :: Par Integer
--           return $ x+y              -- :: return $ x+y :: Par Integer
          rref <- new
          fork $ put rref $ x+y -- sinnlos, nur zur Demonstration!
          get rref

  in print s



  --------------------------------------------------------------
  --  2.TEIL:
  --------------------------------------------------------------

-- Zur Übung definieren wir einige bekannte Datentypen
-- noch einmal neu unter anderen Namen:

-- Booleans
--     Bool     True    False
data MyBool = MyTrue | MyFalse
 deriving Show

-- Der Unit Typ
--        ()        ()
data MyUnitType = MyUnitConstructor
 deriving Show

-- Listen
--        [a]     []      (:)
data MyList a = MyNil | MyCons a (MyList a)
  deriving Show


-- Instanzdeklaration für NFData für unseren Listentyp:
instance (NFData a) => NFData (MyList a) where
  rnf (MyNil)      = ()
  rnf (MyCons h t) = seq (rnf h) (rnf t)

-- Warum man das erste rnf nicht weglassen darf,
-- sieht man erst bei veschachtelten Datentypen
-- Ersetze oben die Definition durch:
--   rnf (MyCons h t) = seq (h) (rnf t)
-- Dann passiert folgendess
-- > :sprint testListe2
-- testListe2 = _
-- > rnf testListe2
-- > :sprint testListe2
-- testListe2 = MyCons (1 : _) (MyCons (3 : _) (MyCons (6 : _) MyNil))
--
-- Es sollte aber sein:
-- > :sprint testListe2
-- testListe2 = MyCons [1,2,3,4,5] (MyCons [3,4,5,6] (MyCons [6,7,8,9] MyNil))


f :: Int -> Int -- irgendeine Funktion, damit wir Thunks statt Werte bekommen
f x = 2*x

testListe :: MyList Int
testListe  = MyCons (f 1) $ MyCons (f 2) $ MyCons (f 3) MyNil
testListe1 = MyCons (f 1) $ MyCons (f 2) $ MyCons (f 3) MyNil
testListe2 = MyCons ([1..5]) $ MyCons ([3..6]) $ MyCons ([6..9]) MyNil
tl3 :: [Int]
tl3 = [undefined,error "autsch",undefined,42,undefined]

myTake :: Int -> MyList a -> MyList a
myTake n (MyCons h t)
  | n > 0 = MyCons h (myTake (n-1) t)
myTake _  _ = MyNil

myLength :: MyList a -> Int
myLength (MyNil) = 0
myLength (MyCons _ t) = 1 + (myLength t)

{- take erzwingt die vollständige Auswertung der ersten Listenglieder zur Anzeige;
   aber length erzwingt nur die Auswertung der Listenknoten, denn die Werte innerhalb der
   Liste werden dazu ja gar nicht benötigt:
> :sprint testListe
testListe1 = _
*Main
> myTake 2 testListe
MyCons 2 (MyCons 4 MyNil)
it :: MyList Int
*Main
> :sprint testListe
testListe1 = MyCons 2 (MyCons 4 (MyCons _ _))
*Main
> :sprint testListe1
testListe = _
*Main
> myLength testListe1
3
it :: Int
*Main
> :sprint testListe1
testListe = MyCons _ (MyCons _ (MyCons _ MyNil))
*Main
>

Deshalb funktioniert z.B. auch
  > length [undefined,error "autsch",undefined,undefined]
  4
  > tl3 !! 3
  42
  > :sprint tl3
  tl3 = [_,_,_,42,_]

-}




























Artikelaktionen


Funktionsleiste