Haskell/Stałe i funkcje

Z Wikibooks, biblioteki wolnych podręczników.

Stałe[edytuj]

Interpreter GHCi pozwala na wykonywanie operacji arytmetycznych poprzez bezpośrednie wpisanie ich w linii poleceń interpretera. Na przykład można obliczyć pole koła o promieniu 5 w następujący sposób:

Prelude> 3.14159265358979323846264338327950 * 5 * 5
78.53981633974483

Jeśli następnie chcielibyśmy obliczyć obwód tego koła, konieczne było by ponowne wpisanie wartości liczby pi. GHCi pozwala na definiowanie stałych za pomocą słowa kluczowego let. Po jednokrotnym zdefiniowaniu wartości pi można używać jej w dalszych obliczeniach. Nazwy stałych (oraz funkcji) muszą rozpoczynać się od małej litery.

Prelude> let pi = 3.14159265358979323846264338327950
Prelude> pi
3.141592653589793

Liczby są „obcinane” do 16 cyfr jedynie podczas wyświetlania.

Prelude> pi * 5 * 5
78.53981633974483

Jeśli chcielibyśmy również promień zastąpić stałą r możemy napotkać pewien problem.

 Prelude> let r = 5
 Prelude> pi*r*r
 <interactive>:1:5:
    Couldn't match expected type `Double' 
	against `Integer'
      Expected type: Double
      Inferred type: Integer
    In the second argument of `(*)', namely `r'
    In the first argument of `(*)', namely `r', namely `pi * r'

Problem ten spowodowany jest ścisłą kontrolą zgodności typów, a dokładniej tym, że Haskell nie pozwala na pomnożenie liczby typu Double przez liczbę typu Integer. Rozwiązaniem tego problemu może być zdefiniowanie stałej r jako liczby rzeczywistej:

Prelude> let r = 5.0

Stałe nie muszą być definiowane bezpośrednio jako liczby. Mogą być zdefiniowane na przykład jako wyrażenie arytmetyczne:

Prelude> let poleKola = pi * r * r
Prelude> poleKola
78.53981633974483

Należy jednak pamiętać, że wartość stałej jest niezmienna (tym się różni od występujących w innych językach tzw. zmiennych). Niemożliwe jest więc obliczenie pola koła o promieniu 2 w następujący sposób:

Prelude> let r = 2.0
Prelude> poleKola
78.53981633974483

Funkcje[edytuj]

Wygodnym rozwiązaniem tego problemu jest zdefiniowanie funkcji przyjmującej jako parametr długość promienia koła.

Prelude> let poleKola r = pi * r * r
Prelude> poleKola 5
78.53981633974483
Prelude> poleKola 1
3.141592653589793

Stała r wewnątrz funkcji poleKola jest stałą lokalną. Wartość stałej globalnej o tej samej nazwie nie ma żadnego wpływu na działanie funkcji.

Warto zauważyć, że tym razem możliwe jest obliczenie pola koła o promieniu 5 (nie musi to być 5.0). Typ wartości liczbowej jest ustalany na podstawie kontekstu w jakim występuje. Podczas definicji stałej r nie było możliwe wywnioskowanie, że ma to być liczba rzeczywista. Podczas wywołania funkcji poleKola z parametrem jest to możliwe. Parametr przekazany do funkcji jest mnożony przez liczbę rzeczywistą (pi), więc powinien być liczbą tego samego typu. Dzięki temu Haskell traktuje liczbę 5 jako Double.

Oczywiście możliwe jest zdefiniowanie funkcji przyjmującej więcej niż jeden parametr, na przykład obliczającej pole prostokąta:

Prelude> let poleProstokata a b = a * b 
Prelude> poleProstokata 2 4
8

Można również zdefiniować funkcję, która do wyznaczenia wartości wykorzysta inne funkcje. Na przykład funkcja licząca objętość prostopadłościanu

Prelude> let objProstopadloscianu a b h = poleProstokata a b * h
Prelude> objProstopadloscianu 1 2 3
6

Funkcje liczące pola graniastosłupów[edytuj]

Powyżej zostały zdefiniowane funkcje obliczające pole koła i prostokąta. Na ich podstawie w prosty sposób można zdefiniować funkcje wyznaczające objętość różnych graniastosłupów. Objętość dowolnego graniastosłupa obliczamy mnożąc pole podstawy razy wysokość. Na początek napiszmy więc taką funkcję:

Prelude>let objGran polePodst h = polePodst * h

Teraz możemy już zdefiniować funkcje liczącą objętość prostopadłościanu, walca lub sześcianu:

Prelude> let objProstopadloscianu a b h = objGran (poleProstokata a b) h
Prelude> let objWalca r h = objGran (poleKola r) h
Prelude> let objSzescianu a = objGran (poleProstokata a a) a