-
Notifications
You must be signed in to change notification settings - Fork 29
Add DebuggingLog #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add DebuggingLog #161
Changes from all commits
faace1f
3f48ff0
58aa7ea
e80f862
2673bfb
7a9d757
52638ae
2f27d8b
6dc0764
d5bceb9
c54aab9
c773533
33135af
0c7ced9
106f040
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| /bower_components/ | ||
| /node_modules/ | ||
| /.pulp-cache/ | ||
| /output/ | ||
| /generated-docs/ | ||
| /.psc-package/ | ||
| /.psc* | ||
| /.purs* | ||
| /.psa* | ||
| /.spago | ||
| /web-dist/ | ||
| /prod-dist/ | ||
| /prod/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # DebuggingLog | ||
|
|
||
| This recipe shows how to do print-debugging using the `Debug` module's `spy` and `traceM` functions. The compiler will emit warnings to remind you to remove these debug functions before you ship production code. | ||
|
|
||
| ## Expected Behavior: | ||
|
|
||
| Does console-printing-based debugging in various contexts to show the pros/cons of each approach and how reliable/unpredictable they can be. | ||
|
|
||
| For the browser, make sure to open the console with dev tools first, then reload/refresh the page. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| This file just indicates that the node backend is supported. | ||
| It is used for CI and autogeneration purposes. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { name = "DebuggingLog" | ||
| , dependencies = | ||
| [ "aff", "console", "debug", "effect", "psci-support", "st" ] | ||
| , packages = ../../packages.dhall | ||
| , sources = [ "recipes/DebuggingLog/src/**/*.purs" ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| module DebuggingLog.Main where | ||
|
|
||
| import Prelude | ||
|
|
||
| import Control.Monad.ST.Internal as ST | ||
| import Data.Tuple (Tuple(..)) | ||
| import Debug.Trace (spy, traceM) | ||
| import Effect (Effect) | ||
| import Effect.Aff (launchAff_) | ||
| import Effect.Class (liftEffect) | ||
| import Effect.Console (log) | ||
|
|
||
| data MyADT = MyADT Int (Tuple Int (Array String)) { foo :: String } | ||
|
|
||
| main :: Effect Unit | ||
| main = do | ||
| log "When we are in the 'Effect' monad, we can print content to the console." | ||
| launchAff_ do | ||
| liftEffect $ log $ "We can still print values to the console as long as \ | ||
| \the monad in question implements the MonadEffect \ | ||
| \type class. Since `Aff` implements MonadEffect, we \ | ||
| \can lift that effect into `Aff`." | ||
|
|
||
| log "However, there are times when we want to debug some code and wish \ | ||
| \to use print-based debugging. Since PureScript is pure, how do we \ | ||
| \do that?" | ||
|
|
||
| usingSpy | ||
|
|
||
| usingTraceM | ||
|
|
||
| compareSpyAndTraceM | ||
|
|
||
| usingSpy :: Effect Unit | ||
| usingSpy = do | ||
| log "usingSpy" | ||
| -- `spy` returns the value it receives. However, it prints that value | ||
| -- to the console before it "returns." | ||
| -- spy :: forall a. DebugWarning => String -> a -> a | ||
| -- You can use this in a `let` clause pretty reliably | ||
| let | ||
| x = 5 | ||
| y = spy "y" 8 | ||
| adt = spy "adt" $ MyADT 1 (Tuple 4 ["a", "b"]) { foo: "foo value" } | ||
| function = spy "function" $ \intValue -> show $ 4 + intValue | ||
|
|
||
| -- quick way of debugging something without showing it or using a | ||
| -- variable name | ||
| _ = spy "debug for me what x + y is" $ x + y | ||
| arrayOfStrings = spy "debug some array" $ map show [1, 2, 3, 4, 5] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One other place it's common to use render state =
HH.div
[ ]
[ HH.text state.someValue ]becomes ...
[ HH.text $ spy "state.someValue" state.someValue ]This makes Another example: let's say you've written a little algorithm with a loop and you want to spy at each step: fact :: Int -> Int -> Int
fact 0 acc = acc
fact n acc = fact (spy "n" (n - 1)) (spy "acc" (acc * n))Being able to insert
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the |
||
|
|
||
| -- quickly drop-in `spy` to see every step of a recursive function | ||
| fact :: Int -> Int -> Int | ||
| fact 0 acc = acc | ||
| fact n acc = fact (spy "n" (n - 1)) (spy "acc" (acc * n)) | ||
|
|
||
| _ = fact 5 1 | ||
|
|
||
| log $ "Thus, spying is an effective way of quickly adding debugging where \ | ||
| \you need it without affecting any other part of your code. \ | ||
| \Note: you should not use `spy` to do logging in production code. \ | ||
| \Use a proper logger in production code." | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some comments on what to expect in
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe |
||
| usingTraceM :: Effect Unit | ||
| usingTraceM = do | ||
| log "usingTraceM" | ||
| traceM "Notice how this text's color is different than what is outputted \ | ||
| \via `log`." | ||
|
|
||
| let | ||
| localMutationComputation | ||
| :: forall ensureMutationStaysLocal. ST.ST ensureMutationStaysLocal Int | ||
| localMutationComputation = do | ||
| -- the ST monad does not implement `MonadEffect`, | ||
| -- so `traceM` is the only way to log output to the console in a | ||
| -- `log`-like fashion. | ||
| localReference <- ST.new 0 | ||
| traceM localReference | ||
| four <- ST.modify (_ + 4) localReference | ||
| traceM four | ||
| ST.write (four + 2) localReference | ||
|
|
||
| log $ "Local reference value is: " <> show (ST.run localMutationComputation) | ||
|
|
||
| compareSpyAndTraceM :: Effect Unit | ||
| compareSpyAndTraceM = do | ||
| let x = 5 | ||
| _ = spy "x" x | ||
| traceM x | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <!DOCTYPE html> | ||
| <html> | ||
|
|
||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <title>DebuggingLog</title> | ||
| </head> | ||
|
|
||
| <body> | ||
| <script src="./index.js"></script> | ||
| </body> | ||
|
|
||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| "use strict"; | ||
| require("../../../output/DebuggingLog.Main/index.js").main(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might also want to include that these functions include a compiler warning, which helps ensure this code gets removed in say the code review process rather than make it to production.
It's similar to why some folks define a custom
todofunction like this:which allows you to make a TODO comment that also includes a compiler warning so you don't forget it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I've updated the readme to include a note about this, so that it shows up in the recipe ToC, too.