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
* Use `traceM`/`traceIO` when you're in monadic code (IO, StateT, etc.). The file already points out `traceIO` and `traceM` as standard options.
486
+
* Use `traceM`/`traceIO` when you're in monadic code (`IO`, `StateT`, etc.). The file already points out `traceIO` and `traceM` as standard options.
487
487
* Laziness gotcha: sometimes nothing prints because the value isn't demanded yet. If you expect a trace and don't see it, ensure the expression is actually evaluated (e.g., by printing it, using `evaluate`, or by restructuring so it's forced).
488
488
* Keep traces out of releases: a common pattern is to guard them behind a CPP flag, or keep them local and remove them once fixed.
489
489
@@ -543,7 +543,7 @@ This example is not chosen because it is practical, but because it clearly demon
543
543
* a reasonable algorithm,
544
544
* and low-level optimizations.
545
545
546
-
### 1. Naive Fibonacci
546
+
### Case 0: Naive Fibonacci
547
547
548
548
```haskell
549
549
fibonacci::Integer->Integer
@@ -741,7 +741,7 @@ main = do
741
741
print (sumGood [1..10000000])
742
742
```
743
743
744
-
### 2. The biggest optimization: a better algorithm
744
+
### Case 1: The biggest optimization: a better algorithm
745
745
746
746
The main problem with the naive Fibonacci implementation is not laziness, boxing, or the choice of numeric type. The real problem is the **algorithm itself**.
747
747
@@ -771,7 +771,7 @@ Now we can benchmark and profile these implementations to see the dramatic impro
771
771
772
772
Low-level optimizations can improve a good implementation, but they rarely compensate for a poor algorithm.
773
773
774
-
### 3. Strict evaluation
774
+
### Case 2: Strict evaluation
775
775
776
776
Even after choosing a much better algorithm, evaluation strategy still matters.
777
777
@@ -804,7 +804,7 @@ The important lesson is that strictness is usually a secondary optimization:
804
804
805
805
Strictness can make a good implementation better, but it does not change the fundamental complexity of the problem.
806
806
807
-
### 4. Choosing the right types
807
+
### Case 3: Choosing the right types
808
808
809
809
The next question is whether we are using the most appropriate data type.
810
810
@@ -835,7 +835,7 @@ However, `Int` has a fixed size and can overflow. That means it is only appropri
835
835
836
836
Choosing the right type will usually not matter as much as choosing the right algorithm, but it can still provide a noticeable improvement once the algorithm is already good. This is of course different when it comes to **types of data structures**, where the choice of representation can have a significant impact on performance.
837
837
838
-
### 5. Boxed vs unboxed values (advanced)
838
+
### Case 4: Boxed vs unboxed values (advanced)
839
839
840
840
Another source of overhead in Haskell is how values are represented in memory.
841
841
@@ -911,7 +911,7 @@ main = print (fibonacciUnboxed 30)
911
911
912
912
Note that we are using `Int` and cannot use `Integer` here, because `Integer` is a boxed type and cannot be unboxed. This code is more efficient than the boxed version, but it is also more complex and less flexible. It is generally recommended to let GHC handle unboxing for you by writing clear, strict code with appropriate types.
913
913
914
-
### 6. Compiler optimizations
914
+
### Case 5: Compiler optimizations
915
915
916
916
So far, all improvements were made by changing the source code. However, the compiler itself can significantly improve performance.
917
917
@@ -938,7 +938,7 @@ ghc-options:
938
938
- -O2
939
939
```
940
940
941
-
### 7. Parallelism and concurrency
941
+
### Case 6: Parallelism and concurrency
942
942
943
943
Another possible optimization is to use multiple CPU cores. This can help when:
Here, `-N` uses all available cores, while `-N4` limits it to 4 cores. Without this option, the program may still use concurrency abstractions, but it will not execute pure computations in parallel across multiple cores.
1122
1122
1123
-
### 8. Foreign Function Interface (FFI)
1123
+
### Case 7: Foreign Function Interface (FFI)
1124
1124
1125
1125
Another way to improve performance, or to reuse existing code, is to call functions written in another language.
1126
1126
@@ -1429,14 +1429,14 @@ The homework to practice IO (again), testing, and writing project documentation
1429
1429
1430
1430
## Further reading
1431
1431
1432
-
* [A Gentle Introduction to Haskell - Input/Output](https://www.haskell.org/tutorial/io.html)
1433
-
* [Haskell - Simple input and output](https://en.wikibooks.org/wiki/Haskell/Simple_input_and_output)
1434
-
* [Real World Haskell - Testing and quality assurance](http://book.realworldhaskell.org/read/testing-and-quality-assurance.html)
0 commit comments