You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Move textual types from 04 to 03
* Improve title and move references
* Moving stuff between 4,5,6
* Rename 4,5,6 according to content
* Fix and improve tut04
* Merging 07 into 05
* Reordering tutorials
* Shorten 5th tutorial (move to 6th)
* Minor fix of tut05
* Minor improvements in tut06
* Finalizing TUT06
* Improve structure in tut07
* HW info fix
* Fix hw and add ginger to tut08
* Add elm intro
* Add elm TEA
* Add link to examples to Elm TEA
* Add Elm Web Apps
* Add Elm Real World Use Cases
* Update links to materials in Elm tutorials
* Create project-guide.md
* Monad transformers added
* Init TH bonus tutorial
* Fix code quotes
* Template Haskell bonus tut
* Images for project guide
Copy file name to clipboardExpand all lines: tutorials/03_branching.md
+204-1Lines changed: 204 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,4 @@
1
-
# Structurationand branching
1
+
# Structuration, branching, and evaluation
2
2
3
3
## If and case
4
4
@@ -417,6 +417,80 @@ show $ getSiblingsOf $ getParentOf $ head people -- A bit nicer
417
417
show . getSiblingsOf . getParentOf . head $ people -- Haskell way (will be covered later on)
418
418
```
419
419
420
+
### List comprehensions
421
+
422
+
Creation of lists using a constructor (or its syntactic sugar) is pretty straightforward, but there are two more interesting ways for that. First is used basically for basic ranges and it is called "dot dot notation". You have seen it already. It works with types that are instances of type class `Enum` (you can check within GHCi by `:info Enum`. You can specify start, step and end of the range (inclusive), but you need to be careful with floats and doubles because of their precision - the error cumulatively grows.
A more flexible way is offered by [list comprehensions](https://wiki.haskell.org/List_comprehension). This concept/construct is nowadays used in many other programming languages, as well, such as Python. In "list" you first specify an expression with variables and then after pipe `|`, there are specifications of bindings and restrictions. It is also possible to define local names with `let`.
As we've already seen, Haskell has lazy non-strict evaluation strategy. It means that no expression is evaluated, unless the value is needed. One of the possibilities is creating infinite lists. You may use `undefined` for testing when the expression is evaluated.
error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
473
+
undefined, called at <interactive>:37:5 in interactive:Ghci23
474
+
```
475
+
476
+
(For stopping output press CTRL+C in GHCi)
477
+
478
+
### Strictness with types
479
+
480
+
In the previous lesson, we touched the topic of enforcing strictness with `!` in patterns ([bang patterns](https://ocharles.org.uk/blog/posts/2014-12-05-bang-patterns.html)) and in function application with `$!` operator. Similarly, we can use `!` with type fields like this:
481
+
482
+
```haskell
483
+
dataMyType=MyConstrInt!Int
484
+
485
+
dataMyRec=MyRecConstr{xA::Int
486
+
, xB::!Int
487
+
}
488
+
```
489
+
490
+
For both cases it means that when data constructor is evaluated, it must fully evaluate ([weak head normal form](https://wiki.haskell.org/Weak_head_normal_form)) the second parameter, but the first one will stay unevaluated in a lazy way.All depends on language implementation in the used compiler.
491
+
492
+
In order to achieve laziness, Haskell wraps all types with some additional information =*boxed types*.If you don't need laziness and other related properties, it is more efficient to use raw *unboxed types*.We will talk about that as a bonus or at the end of course in the *Performance* section.Now you just need to know roughly what is it about, because it is used in some textual types...
493
+
420
494
## Modules and imports
421
495
422
496
AHaskell program consists of a collection of modules (similar to other programming languages).In the top level, you can declare and define data types, function, typeclasses and their instances, pattern bindings and so on.
@@ -523,6 +597,130 @@ x = myFunc1 10 -- a function from TestModule
523
597
y =FPTM.myFunc1 25
524
598
```
525
599
600
+
## Textual types
601
+
602
+
Textual types [(strings)](https://wiki.haskell.org/Strings) are kind of pain in Haskell. This is mostly because of its long legacy and also laziness/strictness trade-offs. However, as everything, they are not really insidious, just not convenient as they could be (and actually are in newer "Haskells", such as PureScript).
603
+
604
+
### String
605
+
606
+
[String](https://hackage.haskell.org/package/base/docs/Data-String.html) is the string type in the `base` package. It is just a type synonym for `[Char]`, so it comes with all properties of a [list](https://hackage.haskell.org/package/base/docs/Data-List.html), and as such, it is the most common one, especially for non-performance-sensitive applications. But when it comes to performance (and sometimes even Unicode behavior), then problems arise - `String` has big overhead in time and space.
607
+
608
+
### Text
609
+
610
+
[Data.Text](https://hackage.haskell.org/package/text/docs/Data-Text.html) from [text](https://hackage.haskell.org/package/text) package is a time and space-efficient implementation of Unicode text. You can convert between `Text` and `String` with functions `pack` and `unpack`. The `Data.Text` package exports functions with same names as there are for `String` (`head`, `length`, `map`, `replace`, etc.), so the advised import style is `import qualified Data.Text as T`.
611
+
612
+
```
613
+
Prelude> import qualified Data.Text as T
614
+
Prelude T> txt = T.pack "my effective text"
615
+
Prelude T> :type txt
616
+
txt :: T.Text
617
+
Prelude T> T.index txt 1
618
+
'y'
619
+
Prelude T> T.replace "my" "your" txt
620
+
621
+
<interactive>:13:11: error:
622
+
• Couldn't match expected type ‘T.Text’ with actual type ‘[Char]’
623
+
• In the first argument of ‘T.replace’, namely ‘"my"’
624
+
In the expression: T.replace "my" "your" txt
625
+
In an equation for ‘it’: it = T.replace "my" "your" txt
626
+
627
+
<interactive>:13:16: error:
628
+
• Couldn't match expected type ‘T.Text’ with actual type ‘[Char]’
629
+
• In the second argument of ‘T.replace’, namely ‘"your"’
630
+
In the expression: T.replace "my" "your" txt
631
+
In an equation for ‘it’: it = T.replace "my" "your" txt
• Couldn't match expected type ‘[a0]’ with actual type ‘T.Text’
638
+
• In the first argument of ‘length’, namely ‘txt’
639
+
In the expression: length txt
640
+
In an equation for ‘it’: it = length txt
641
+
Prelude T> T.length txt
642
+
17
643
+
```
644
+
645
+
There is another variant of the Text package, which is [Data.Text.Lazy](https://hackage.haskell.org/package/text/docs/Data-Text-Lazy.html), which exports same operations and thanks to laziness, it can work with huge texts and it may provide better performance under the right circumstances. [Data.Text.Encoding](https://hackage.haskell.org/package/text/docs/Data-Text-Encoding.html) (and its lazy alternative) may be also useful.
646
+
647
+
### ByteString
648
+
649
+
Last of the types mentioned here is [Data.ByteString](https://hackage.haskell.org/package/bytestring/docs/Data-ByteString.html) from [bytestring](https://hackage.haskell.org/package/bytestring) package. Byte vectors are encoded as strict Word8 arrays of bytes and they are used for interoperability between Haskell and C or other lower-level situations. In many ways, the usage is similar to [text](https://hackage.haskell.org/package/text) package (again `pack` and `unpack`, same basic functions, `Lazy` alternative, and so on). Next, there is an option to use vectors with `Char8` instead of `Word8`, which works as Unicode subset (0-255) strings and it is used when working with pure ASCII string representations.
650
+
651
+
```
652
+
Prelude T> import Data.ByteString as B
653
+
Prelude T B> bstr = B.pack [97, 98, 99]
654
+
Prelude T B> bstr
655
+
"abc"
656
+
Prelude T B> index bstr 2
657
+
99
658
+
Prelude T B> B.map (+1) bstr
659
+
"bcd"
660
+
661
+
Prelude T B> import qualified Data.ByteString.Char8 as C
662
+
Prelude T B C> C.pack "abc"
663
+
"abc"
664
+
Prelude T B C> B.pack "abc"
665
+
666
+
<interactive>:28:8: error:
667
+
• Couldn't match type ‘Char’ with ‘GHC.Word.Word8’
668
+
Expected type: [GHC.Word.Word8]
669
+
Actual type: [Char]
670
+
• In the first argument of ‘pack’, namely ‘"abc"’
671
+
In the expression: pack "abc"
672
+
In an equation for ‘it’: it = pack "abc"
673
+
Prelude T B C> cstr = C.pack "abc"
674
+
Prelude T B C> C.index cstr 2
675
+
'c'
676
+
```
677
+
678
+
In other cases you need to use encoding to encode/decode bytes to/from text:
679
+
680
+
```
681
+
Prelude T B> import qualified Data.Text.Encoding as E
682
+
Prelude T B C E> E.encodeUtf8 (T.pack "život, жизнь, lífið, ਜੀਵਨ, ,حياة")
As needing to pack all string literals when using non-base string representations is cumbersome, there is a handy [GHC] language extension [OverloadedStrings](https://ocharles.org.uk/blog/posts/2014-12-17-overloaded-strings.html).
696
+
697
+
Generally, [GHC] language extensions can be enabled in the source file using pragma `LANGUAGE` as the first line in the file:
698
+
699
+
```haskell
700
+
{-# LANGUAGE OverloadedStrings #-}
701
+
702
+
moduleXY...
703
+
```
704
+
705
+
InGHCi, the extension can be enabled using the `:set` directive:
706
+
707
+
```
708
+
Prelude> :set -XOverloadedStrings
709
+
```
710
+
711
+
After that, a string literal type can be inferred by its usage in the source code:
712
+
713
+
```
714
+
Prelude> import qualified Data.Text as T
715
+
Prelude T> :type "abc"
716
+
"abc" :: [Char]
717
+
Prelude T> :set -XOverloadedStrings
718
+
Prelude> :type "abc"
719
+
"abc" :: Data.String.IsString p => p
720
+
Prelude T> T.length "abc" -- no need to pack the literal any more!
721
+
3
722
+
```
723
+
526
724
## Task assignment
527
725
528
726
The homework to practice branching and slightly working with modules is in repository [MI-AFP/hw03](https://github.com/MI-AFP/hw03).
@@ -532,8 +730,13 @@ The homework to practice branching and slightly working with modules is in repos
532
730
* [Learn You a Haskell for Great Good](http://learnyouahaskell.com) (chapters 4, 7)
0 commit comments