Laisk väärtustamine

**Laisk väärtustamine** (inglise keeles *lazy evaluation*) ehk **mitterange väärtustamine** on programmeerimiskeelte teoorias väärtustamismeetod, kus avaldis väärtustatakse hetkel, kui avaldise väärtust vajatakse. Samuti väldib laisk väärtustamine korduvaid väärtustamisi, mis võib aidata funktsioonide tööaega eksponentsiaalselt vähendada võrreldes mitterangete väärtustamismeetoditega. 

Laisa väärtustamisega

* on võimalus defineerida potentsiaalselt lõpmatuid andmestruktuure, mis võib lihtsustada teatud algoritmide teostamist;
* suureneb jõudlus tarbetute arvutuste tegematajätmise arvelt.

Laisk väärtustamine aitab ka mälu kokku hoida, sest väärtused leitakse nende vajamise hetkel. Siiski on laiska väärtustamist keeruline kombineerida imperatiivse programmeerimise võimalustega nagu näiteks erinditöötlus ja sisend/väljund, sest operatsioonide järjekord pole enam deterministlik. Laisa väärtustamise tõttu võivad tekkida mälulekked.  

Laisa väärtustamise vastand on agar väärtustamine, tuntud ka kui range väärtustamine. Agarat väärtustamist kasutatakse enamikus programmeerimiskeeltes.

## Rakendused
Viivitusega väärtustamist kasutatakse tihti funktsionaalsetes programmeerimiskeeltes. Viivitusega väärtustamisel ei väärtustata avaldist selle muutjaga sidumise hetkel, vaid kui väärtustaja on sunnitud avaldise väärtust kasutama. Näiteks avaldises `x = avaldis` (avaldise väärtuse omistamine muutujale x) on selgelt vaja, et avaldis väärtustataks ning siis omistataks muutujale `x`, kuid mida tegelikult muutujas `x` hoitakse, on tähtsusetu, kuni on reaalne vajadus selle muutuja väärtuse järele.

Hilise väärtustamise eelis on lõpmatute massiivide loomine ilma lõpmatute tsükliteta. Näiteks võimaldab see luua funktsioon Fibonacci jada genereerimiseks, mis koostab lõpmatu arvujada (tihti kutsutakse seda vooks). Positsioonil *n* asuva Fibonacci arvu saamiseks on lõpmatust massiivist vaja võtta vastaval kohal asuv element ja selleks on vaja massiivis väärtustada *n* esimest elementi. 

Näiteks programmeerimiskeeles Haskell on võimalik täielikku Fibonacci jada koostada järgmiselt: 


```haskell
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
```


Haskelli süntaksis `:` lisab elemendi massiivi, `tail` tagastab massiivi ilma esimese elemendita ning `zipWith` võtab argumendiks funktsiooni (praegusel juhul liitmise), et kombineerida vastava kahe massiivi elemendid kolmandaks. 

## Laiskus ja agarus
Laiskades programmeerimiskeeltes nagu Haskell on vaikeväärtustamismeetod laisk väärtustamine, aga teatud juhtudel on võimalik koodi muuta agaramaks või vastupidi – muuta koodi laisemaks pärast selle eelnevalt agaramaks muutmist. Seda saab teha, kui programmeerida midagi, mis sunnib väärtustama (teeb koodi agaramaks) või väldib väärtustamist (teeb koodi laisemaks). Range väärtustamine tähendab tavaliselt agarust, aga need on tehniliselt erinevad mõisted.

#### Laiskuse simuleerimine agarates keeltes

##### Python
Programmeerimiskeele Python teises versioonis on funktsioon `range()`, mis tagastab täisarvude loendi. Terve loend on salvestatud mällu, kui esimene omistuslause on väärtustatud, nii et see on näide agarast või kohesest väärtustamisest:

```python
>>> r = range(10)
 >>> print r
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 >>> print r[3]
 3
```


Pythoni kolmandas versioonis on funktsioon `range()`, mis tagastab spetsiaalse vahemiku objekti ja mis arvutab loendi elemendi ainult siis, kui seda on vaja teha. Vahemiku objekti elemendid genereeritakse ainult siis, kui neid on vaja (näiteks `print(r[3])` järgnevas koodilõigus), nii et see on näide laisast väärtustamisest.


```python
>>> r = range(10)
 >>> print(r)
 range(0, 10)
 >>> print(r[3])
 3
```


## Viited