8

What is Racket's equivalent for viewing and changing the working directory of a process like pwd and cd?

Sage Gerard
  • 1,311
  • 8
  • 29

2 Answers2

12

Use current-directory.

Passing no arguments returns the current working directory. Passing a path changes the working directory to that path.

Here's an example for the REPL that prints the current directory, then changes to the parent directory:

> (current-directory)
#<path:/home/sage/>
> (current-directory (build-path (current-directory) ".."))
; now in /home
Sage Gerard
  • 1,311
  • 8
  • 29
1

Note that path is a type-object in racket. And because in Racket current-directory does not actually change the environment path but only changes the current-directory path value, if you do this:

> (current-directory "/somepath/thatdoesnt/exist/") ; now in /somepath/thatdoesnt/exist

Racket will not throw an error. You'll only get an error when you try to do something with the path object itself.

such as:

> (directory-list (current-directory)) ; directory-list: could not open directory ; path: /somepath/thatdoesnt/exist/ ; system error: No such file or directory; errno=2 ; [,bt for context]

Jason Hemann
  • 327
  • 1
  • 12
calvin
  • 19
  • 1
  • 1
    I wouldn't call that "lazy evaluation". In Python I can `current_dir = "/bad/path"` which doesn't error anything, but when I use it in `os.listdir` it now errors. Does that mean Python is lazily evaluated as well? – Sorawee Porncharoenwase Jul 25 '19 at 03:17
  • the difference is that in Python `os.listdir` takes a string as it's input. your `current_dir` is a string. directory-list in Racket requires a path object. Racket's `current-directory` converts a string to path object... sort of. `(path? (current-directory "/badpath"))` will not evaluate `(current-directory "/badpath")` so it is #f. do `(string->path "/badpath")` to create a valid path object. But a path object will not evaluate to an actual path until it is evaluated in another function, like when directory-list occurs. In Python, `os.chdir('/badpath')` fails immediately, not lazily. – calvin Jul 26 '19 at 17:10
  • `> (current-directory "/badpath") ; now in /badpath` does not actually change the environment path. it changes the current-directory path value. The message is misleading. it will only evaluate to an os path when it's used. – calvin Jul 26 '19 at 17:22
  • I just saw the reply, so let me respond. 1) in Racket, there is no real difference in path objects and strings. They can both point to non-existing file. Python, too, has the same behavior. Try `from pathlib import Path; p = Path('this-does-not-exist')`. It doesn't error. 2) No, `directory-list` doesn't require only a path object. It also accepts a string. Most path functions in Racket can accept either strings or paths, where strings are effectively converted into paths first. – Sorawee Porncharoenwase Jan 24 '22 at 01:38
  • 3) `(path? (current-directory "/badpath"))` doesn't make much sense. `(current-directory "/badpath")` returns a `void?` value (it sets the `current-directory` parameter), so `(path? (current...))` will always be `#f`. – Sorawee Porncharoenwase Jan 24 '22 at 01:50
  • 4) you are right that there's a difference between Racket and Python. `os.chdir` is at the OS-level. It issues a system call to change the directory in the system. In contrast, `current-directory` is at Racket level (so no system call) and is essentially just a variable, where various Racket functions like `directory-list` consult it to find what the current directory is. I understand why you might view that as "lazy evaluation". The checking is indeed postponed until a system call is actually needed. Still, this is not "lazy evaluation" which is used to describe behavior of function call. – Sorawee Porncharoenwase Jan 24 '22 at 01:56