{"action":"created","issue":{"url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/168","repository_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library","labels_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/168/labels{/name}","comments_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/168/comments","events_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/168/events","html_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/issues/168","id":174602817,"number":168,"title":"How to use ls? Could it be made easier?","user":{"login":"dogweather","id":150670,"avatar_url":"https://avatars.githubusercontent.com/u/150670?v=3","gravatar_id":"","url":"https://api.github.com/users/dogweather","html_url":"https://github.com/dogweather","followers_url":"https://api.github.com/users/dogweather/followers","following_url":"https://api.github.com/users/dogweather/following{/other_user}","gists_url":"https://api.github.com/users/dogweather/gists{/gist_id}","starred_url":"https://api.github.com/users/dogweather/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dogweather/subscriptions","organizations_url":"https://api.github.com/users/dogweather/orgs","repos_url":"https://api.github.com/users/dogweather/repos","events_url":"https://api.github.com/users/dogweather/events{/privacy}","received_events_url":"https://api.github.com/users/dogweather/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2016-09-01T19:13:55Z","updated_at":"2016-09-05T09:40:17Z","closed_at":null,"body":"I'm a Haskell beginner, and was following the Turtle tutorial. Part-way through the section on Ghci, I spontaneously tried `ls`, but couldn't see how to use it:\r\n\r\n* `ls`\r\n* `ls pwd`\r\n* `ls <$> pwd`\r\n* `ls \".\"`\r\n\r\n...these all failed for typing reasons of one kind or another. "},"comment":{"url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/comments/244704320","html_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/issues/168#issuecomment-244704320","issue_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/168","id":244704320,"user":{"login":"Gabriel439","id":1313787,"avatar_url":"https://avatars.githubusercontent.com/u/1313787?v=3","gravatar_id":"","url":"https://api.github.com/users/Gabriel439","html_url":"https://github.com/Gabriel439","followers_url":"https://api.github.com/users/Gabriel439/followers","following_url":"https://api.github.com/users/Gabriel439/following{/other_user}","gists_url":"https://api.github.com/users/Gabriel439/gists{/gist_id}","starred_url":"https://api.github.com/users/Gabriel439/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Gabriel439/subscriptions","organizations_url":"https://api.github.com/users/Gabriel439/orgs","repos_url":"https://api.github.com/users/Gabriel439/repos","events_url":"https://api.github.com/users/Gabriel439/events{/privacy}","received_events_url":"https://api.github.com/users/Gabriel439/received_events","type":"User","site_admin":false},"created_at":"2016-09-05T09:40:17Z","updated_at":"2016-09-05T09:40:17Z","body":"@lspitzner gave the correct answer: enable `OverloadedStrings` and use `view`.  I just want to expand on that to explain why the other versions didn't work:\r\n\r\n### Why `ls` didn't work\r\n\r\n`ls` doesn't work because you gave it no arguments.  The type error you got probably looked something like this:\r\n\r\n```haskell\r\n>>> ls\r\n\r\n<interactive>:4:1:\r\n    No instance for (Show (Turtle.FilePath -> Shell Turtle.FilePath))\r\n      (maybe you haven't applied enough arguments to a function?)\r\n      arising from a use of ‘print’\r\n    In a stmt of an interactive GHCi command: print it\r\n```\r\n\r\nThe reason for the type error is that `ghci` does something like the following algorithm for every command you enter:\r\n\r\n* If the expression you entered is of type `IO a`, for some arbitrary type `a`, then run the `IO` action and then:\r\n    * Don't print the result if the type `a` is actually `()`\r\n    * `print` its result if the type `a` implements `Show`\r\n    * `print` nothing if the type `a` does not implement `Show`\r\n* Otherwise, `print` the result of the expression\r\n\r\nIn this case, the type of `ls` is `FilePath -> Shell FilePath`, which is not of the shape `IO a`, so `ghci` tries to `print` it.\r\n\r\n`print` expects that its argument implements the `Show` interface, but something of type `FilePath -> Shell FilePath` does not implement the `Show` interface because functions are not `Show`able.  This in turn leads to the error message you saw:\r\n\r\n```\r\n    No instance for (Show (Turtle.FilePath -> Shell Turtle.FilePath))\r\n```\r\n\r\n### Why `ls pwd` doesn't work\r\n\r\nThis doesn't work because `ls` expects a `FilePath` but you gave it a subroutine that returns a `FilePath` (i.e. `IO FilePath`).  To make an analogy to ordinary Bash programming, this would be like running:\r\n\r\n```bash\r\n$ ls pwd\r\nls: pwd: No such file or directory\r\n```\r\n\r\n... which gives the wrong behavior because `pwd` is the name of a command and not the name of a file.\r\n\r\nIn `bash`, the way you would work around this is to do something like this:\r\n\r\n```bash\r\n$ DIR=$(pwd)\r\n$ ls $DIR\r\n```\r\n\r\n... and the `turtle` analog of that is:\r\n\r\n```haskell\r\nmain = do\r\n    dir <- pwd\r\n    view (ls dir)\r\n```\r\n\r\nNow let's revisit the type error you got, which was this:\r\n\r\n```\r\n<interactive>:5:4:\r\n    Couldn't match expected type ‘Turtle.FilePath’\r\n                with actual type ‘io0 Turtle.FilePath’\r\n    In the first argument of ‘ls’, namely ‘pwd’\r\n    In the expression: ls pwd\r\n```\r\n\r\nThe compiler arrived that this error by first checking the type of `ls`, which is this:\r\n\r\n```haskell\r\nls :: FilePath -> Shell FilePath\r\n```\r\n\r\n... and then checking the type of `pwd`:\r\n\r\n```haskell\r\npwd :: MonadIO io => io FilePath\r\n```\r\n\r\n... and then comparing the type of `pwd` with the type of the argument to `ls`.  The compiler then notices that the types don't match:\r\n\r\n```haskell\r\nls  ::               FilePath -> Shell FilePath\r\n                     ^\r\n                     | These don't match\r\n                     v\r\npwd :: MonadIO io => io FilePath\r\n```\r\n\r\n... which is what the compiler means when it says that:\r\n\r\n```\r\n    Couldn't match expected type ‘Turtle.FilePath’\r\n                with actual type ‘io0 Turtle.FilePath’\r\n```\r\n\r\n### Why `ls <$> pwd` doesn't work\r\n\r\nThis is actually not a type error, but when you ran it nothing happened.  To see why, let's ask the compiler what the type of the expression is:\r\n\r\n```haskell\r\n>>> :type ls <$> pwd\r\nls <$> pwd :: MonadIO io => io (Shell Turtle.FilePath)\r\n```\r\n\r\nThis is a subroutine whose return result is a stream (or `Shell` in turtle parlance).  In order to view this stream you would have to do something like this:\r\n\r\n```haskell\r\n>>> streamOfFiles <- ls <$> pwd\r\n>>> view streamOfFiles\r\n...\r\n...\r\n```\r\n\r\nIf we revisit `ghci`'s rules for what to print:\r\n\r\n* If the expression you entered is of type `IO a`, for some arbitrary type `a`, then run the `IO` action and then:\r\n    * Don't print the result if the type `a` is actually `()`\r\n    * `print` its result if the type `a` implements `Show`\r\n    * `print` nothing if the type `a` does not implement `Show`\r\n* Otherwise, `print` the result of the expression\r\n\r\n... we'll see that `ghci` doesn't print the `Shell FilePath` returned by `ls <$> pwd` because the `Shell` type does not implement `Show`.  However, the return value is still *there* even if `ghci` can't print it for you.  That's why we're able to store the return value in the `streamOfFiles` variable and then `view` it to see the actual contents.\r\n\r\nNote that this code:\r\n\r\n```haskell\r\nexample1 = do\r\n    streamOfFiles <- ls <$> pwd\r\n    view streamOfFiles\r\n```\r\n\r\n... and this code:\r\n\r\n```haskell\r\nexample2 = do\r\n    dir <- pwd\r\n    view (ls dir)\r\n```\r\n\r\n... do the exact same thing.  In fact, they are guaranteed to do the same thing thanks to the `Monad` laws.\r\n\r\n### Why `ls \".\"` doesn't work\r\n\r\nThis fails for the same reason as the previous example: `ls \".\"` is a `Shell FilePath`, but `ghci` cannot `print` a `Shell FilePath` because it does not implement `Show`.  However, you got a different result this time: a type error!\r\n\r\n```haskell\r\n>>> ls \".\"\r\n\r\n<interactive>:10:1:\r\n    No instance for (Show (Shell Turtle.FilePath))\r\n      arising from a use of ‘print’\r\n    In a stmt of an interactive GHCi command: print it\r\n```\r\n\r\nThis is again due to `ghci`'s rules for how to print things:\r\n\r\n* If the expression you entered is of type `IO a`, for some arbitrary type `a`, then run the `IO` action and then:\r\n    * Don't print the result if the type `a` is actually `()`\r\n    * `print` its result if the type `a` implements `Show`\r\n    * `print` nothing if the type `a` does not implement `Show`\r\n* Otherwise, `print` the result of the expression\r\n\r\nNotice how `ghci` behaves differently if the value is pure versus the result of an `IO` action.  In our previous example (`ls <$> pwd`) the un-`Show`able value was the result of an `IO` action so it was silently ignored.  However, if the un-`Show`able value is pure then it's a type error instead.  It's confusing, I know!\r\n\r\nIn this case the resolution is the same: you can display the stream using `view`.\r\n\r\nIf you want to better build an intuition for these sorts of things I recommend reading the [`Turtle.Tutorial`](https://hackage.haskell.org/package/turtle-1.2.8/docs/Turtle-Tutorial.html) which explains these same concepts in more detail."}}
{"actor":{"display_login":"Gabriel439"}}