Direkt zum Inhalt | Direkt zur Navigation

Sektionen
Benutzerspezifische Werkzeuge

Lösung Blatt 2 - lhs

Uebung02_Musterloesung.lhs — LHS source code, 7Kb

Dateiinhalt

\documentclass{article}
%include lhs2TeX.fmt
%include polycode.fmt
\usepackage[ngerman]{babel}
\usepackage{ucs}
\usepackage[utf8x]{inputenc}
\usepackage{fullpage}
\setlength{\parindent}{0pt}
\begin{document}

\setcounter{section}{1}
\section{ Einfache Typen }

\begin{code}
module Uebung2 where
import Prelude hiding (div, subtract)
\end{code}

Wir definieren noch einmal den Datentypen |Nat| und die Konversionen von und nach |Int|:
\begin{code}
data Nat = O | S Nat deriving (Show, Eq)
\end{code}

\begin{code}
intToNat	:: Int -> Nat
intToNat 0	= (O)
intToNat n	= S ( intToNat (n-1) ) 
\end{code}

\begin{code}
natToInt	:: Nat -> Int
natToInt O	= 0
natToInt (S n)	= 1 + ( natToInt n )
\end{code}

\subsection{Datentypen und Operationen}

\begin{enumerate}

	\item Definieren Sie eine Funktion |intToNatg| analog zu |intToNat| unter Benutzung 
        von guards. Stellen Sie sicher, dass |intToNatg| bei Eingabe einer negativen 
        Zahl eine Fehlermeldung ausgibt. (1pt)
\begin{code}
intToNatg :: Int -> Nat
intToNatg n | n  < 0 = error "Negative integer is undefined for intToNatg"
            | n == 0 = O
            | n  > 0 = S $ intToNatg $ n-1
\end{code}

	\item Definieren Sie die Subtraktion und die (ganzzahlige) Division 
        |subtract, div :: Nat -> Nat -> Nat| so, dass für endliche Elemente |n,m :: Nat| 
        (endliche Elemente sind |O, S O, S (S O),...|) folgende Eigenschaften gelten:
        \begin{enumerate}
         \item |subtract (n+m) n = m |
         \item |div (n*m) n = m|
         \end{enumerate}
        Beweisen Sie diese Eigenschaften! (3pt)

Lösung von HG:

\begin{code}
natPred :: Nat -> Nat
natPred O     = undefined
natPred (S n) = n

subtract :: Nat -> Nat -> Nat
subtract z n | n == O    = z
             | z == O    = undefined
             | otherwise = subtract (natPred z) (natPred n)

div :: Nat -> Nat -> Nat
div z n | n == O    = undefined
        | z == O    = O
        | otherwise = S $ div (subtract z n) n
\end{code}

\begin{quote}
-- Assume |n = O| \\
subtract (O+m) O \\
= {def subtract} \\
(O+m) \\
= {def addition} \\
m \\
\\
-- Assume |n > O| \\
subtract (n+m) n \\
= {def subtract} \\
subtract (natPred (n+m) (natPred n) \\
= {def natPred, n = 1 + n'} \\
subtract (n'+m) n' \\
= {Induction} \\
subtract (O+m) O \\
= {see assumption for n = O} \\
m \\
\\
\\
Die zweite Eigenschaft |(div (n*m) n = m)| kann nicht bewiesen werden,
da sie den Regeln der Division widerspricht. Für n = 0 wäre |div (0*m) 0 = m|
zu beweisen, wobei die Regeln der Division bereits |div _ 0 = undefined|
festlegen. Die Aufgabe ist also nicht lösbar, wenn sowohl die Regeln
der ganzzahligen Division als auch die geforderte Eigenschaft gelten
sollen.
\end{quote}
  \item Viele Funktionen auf dem Datentyp |Nat| kann man durch folgendes Rekursionsprinzip 
        definieren:

\begin{code}
foldNat :: a -> (a -> a) -> Nat -> a
foldNat start next O     = start
foldNat start next (S n) = next ( foldNat start next n)
\end{code}

        Es ist z.B. |id = foldNat O S| und | natToInt = foldNat 0 (+1) |. Definieren Sie 
        Funktionen | isEven |, die für gerade Zahlen |True| und sonst |False| zurückgibt, 
        und |isZero|, die für |O| |True| und sonst |False| zurückgibt, mit Hilfe von 
        |foldNat| (2pt):

\begin{code}
isEven :: Nat -> Bool
isEven = foldNat True not

isZero :: Nat -> Bool
isZero = foldNat True (&&False)
\end{code}

	\item{Vervollständigen Sie die Definition der Implikation: (1pt)

\begin{code}
implies :: Bool -> Bool -> Bool
True  `implies` x  = x
False `implies` _  = True
\end{code}}


\item Beweisen Sie, dass |Jane| und |Dick| verschiedene Typen sind, indem Sie zeigen, dass
      |j2j| nicht die identische Funktion auf |Jane| ist! Definieren Sie dazu eine Funktion 
      |test :: Jane -> Bool| und geben Sie |t :: Jane| so an, dass |test| sich auf |t| 
      anders verhält als auf |j2j t|.(1pt)
        
\begin{code}
data    Jane   = MkJane Int deriving Show
newtype Dick   = MkDick Int deriving Show

j2d :: Jane -> Dick
j2d (MkJane x) = (MkDick x)

d2j :: Dick -> Jane
d2j (MkDick x) = (MkJane x)

j2j :: Jane -> Jane
j2j            = d2j . j2d

test :: Jane -> Bool
test (MkJane _) = False
\end{code}
\end{enumerate}

( t = undefined )

\subsection{Strictness}
\begin{enumerate}
\addtocounter{enumi}{5}
\item Im Seminar hatten wir die boolschen Operatoren |and| und |or| strikt in einer, aber 
      nicht-strikt in der anderen Komponente definiert. Kann man |and| und |or| auch strikt 
      in beiden Argumenten definieren? Falls ja, implementieren Sie diese, falls nein, 
      begründen Sie!(1pt)

\begin{code}

and' :: Bool -> Bool -> Bool

and' True False = False
and' True True = True
and' False True = False
and' False False = False


\end{code}
or' folgt analog

\item Kann man eine nicht-strikte Funktion |not'| definieren, die sich auf True und False wie 
      |not| verhält? Begründen Sie! (1pt)


Funktion soll sich auf True und False unterschiedlich verhalten, muss also ihr Argument 
auswerten. Ist das Argument undefined, kann dann nur undefined zurückgegeben werden.

\end{enumerate}

\subsection{Tupels und Either}

Wir hatten die folgenden Gesetze:\\
1)   |fst . pair (f, g)        =  f|\\
2)   |snd . pair (f, g)        =  g|\\
3)   |pair (f, g) . h          =  pair (f.h,g.h)|\\
4)   |cross (f,g) . pair (h,k) =  pair (f.h,g.k)|\\
i)   |scase (f,g) . Left       = f|\\
ii)  |scase (f,g) . Right      = g|\\
iii) |h . scase (f,g)          = scase (h.f,h.g)|\\
iv)  |scase (f,g) . plus(h,k)  = scase (f.h,g.k)|

\begin{enumerate}
\addtocounter{enumi}{7}

\item  Beweisen Sie iv) unter Benutzung von i)-iii) ( analog zum Beweis von 4) im letzten 
       Seminar).(1pt)

Lösung von HG:

\begin{quote}
scase(f,g) . plus(h,k) \\
= {def plus} \\
scase(f,g) . scase(Left.h,Right.k) \\
= { iii) } \\
scase(scase(f,g).Left.h,scase(f,g).Right.k) \\
= { i) ii) } \\
scase(f.h,g.k)
\end{quote}

\item Beweisen Sie |cross(f,g) . cross(h,k) = cross (f.h,g.k)|. (2pt)

Lösung von HG:

\begin{quote}
cross(f,g) . cross(h,k) \\
= { def cross } \\
pair(f.fst,g.snd) . pair(h.fst,k.snd) \\
= { 3) } \\
pair(f.fst.pair(h.fst,k.snd),g.snd.pair(h.fst,k.snd)) \\
= { 1) 2) } \\
pair(f.h.fst,g.k.snd) \\
= { def cross reverse } \\
cross(f.h,g.k)
\end{quote}

\item Schreiben Sie eine Funktion |testEither :: Either Bool Char -> a| in einen geeigneten 
      Typen |a|, die sich auf |Left undefined|, |Right undefined| und |undefined| 
      unterschiedlich verhält! (1pt)

\begin{code}

testEither :: (Either Bool Char) -> Bool
testEither (Left _)  = True
testEither (Right _) = False

\end{code}


\item Ein Datum kann durch ein Tripel (Jahr,Monat,Tag) angegeben werden. Wir definieren das 
      Typsynonym

\begin{code}
type Date = (Int,Int,Int)
\end{code}

      Implementieren Sie eine Funktion |age:: Date -> Date -> Int| so, dass 
      |age birthday current| das Alter einer Person angibt, wenn |birthday| der Geburtstag 
      der Person und |current| das aktuelle Datum ist. (2pt)

\begin{code}

age :: Date -> Date -> Int
age (by,bm,bd) (cy,cm,cd) 
  | (bm>cm) || ((bm==cm) &&(bd>cd)) = cy - by - 1
  | otherwise                       = cy - by


\end{code}

\end{enumerate}

\subsection{Fibonacci}

\begin{enumerate}
\addtocounter{enumi}{11}

\item Implementieren Sie eine Funktion |fib :: Int -> Integer|, sodass |(fib n)| das 
      $n$-te Glied der Fibonacci-Folge ist: es sei |fib 0 = 0|, |fib 1 = 1| und für alle 
      endlichen (auch negativen!) |n::Int| gelte\\ |fib n = fib (n-1) + fib (n-2)| . (2pt)

\begin{code}

fib :: Int -> Integer
fib n
  | n == 0  = 0
  | n == 1  = 1
  | n > 1   = (fib (n-1)) + (fib (n-2))
  | n < 0   = (fib (n+2)) - (fib (n+1)) 


fibS :: [Integer]
fibS = 1:0:zipWith (-) fibS (tail(fibS))


\end{code}


\end{enumerate}
\end{document}
Artikelaktionen
Auf einen Blick
Lehrform Seminar
Empfohlen ab FS 3
Voraussetzungen Grundkenntnisse der Informatik aus den ersten 4 Semestern, vor allen aus den Bereichen Theoretische Informatik und Logik. Teilnahme an der Veranstaltung "Automatisierte Logik und Programmierung" ist vorteilhaft, aber nicht notwendig.
Benotet Ja
Punkte gesamt 3
davon praktisch 3
Sprache deutsch/englisch
Fremdhörer zugelassen? Nein
Teilgebiete Theoretische Informatik(2000), Praktische Informatik(3000), Wahlfrei(7000)
Studiengang Bachelor, Master
Belegung via PULS