Suppose you prompt for user input with a combination of putStr and getLine:
main = do
putStrLn "A line with line termination" -- printed correctly
putStr "A line without line termination, e.g. to prompt for input: " -- NOT printed
line <- getLine
putStrLn ("You entered: " ++ line)
In contrast to Haskell, Frege does not print the 2nd line (which uses putStr rather than putStrLn). Is this behavior of a missing flush intended?
If Frege deviates from Haskell behavior, I would assume it to mimic Java's behavior instead. A conceptually similar example:
public static void main(String[] args) {
System.out.println("A line with line termination");
System.out.print("A line without line termination, e.g. to prompt for input: ");
String line = new java.util.Scanner(System.in).nextLine();
System.out.println("You entered: " + line);
}
This however behaves like the Haskell variant, i.e. System.out.print gets flushed immediately.
Thanks in advance for any feedback!
PS: The (mis?)behavior can be reproduced with the latest Eclipse-Plugin as well as IntelliJ/Gradle.
Your Java code uses System.out, which is a PrintStream.
The Frege code uses a PrintWriter.
These two classes work a bit differently with respect to flushing. From the docs of PrintWriter:
Unlike the {#link PrintStream} class, if automatic flushing is enabled
it will be done only when one of the println, printf, or format methods is invoked, ..
So for your Frege code, you have to add a stdout.flush after the print to make it appear immediately.
Feel free to file an issue with the request to align Frege with the Haskell behavior in this regard. (We could leave the print as is but make the putStr add the flush automatically.)
Related
I'm doing beginner level Kotlin and I'm trying to do a multi line input and I found this code:
var originalTexts: MutableList<String> = mutableListOf()
while (true) {
val originalText = readLine()
if (originalText == null) break
originalTexts.add(originalText)
}
The problem is I dont know how to input null or EOF in the input stream in console using readLine(). I tried ctrl+z or ctrl+d but is not working. Beginner here please help guys.
Edit: I'm using Intellij in Windows OS
A null return from readLine() indicates an end-of-file condition — basically, there can be no more input.
But whether and how that can happen depends on how you're running the program:
If you're running it in a terminal window, then you can signal end-of-file with a special key combination, which depends on the platform:
On macOS and Linux: Ctrl+D
On Windows: Ctrl+X then Return
If you're running it with the input redirected from a file (e.g. by appending <filename to the command), then you'll get an end-of-file condition after reading all the content of the file.
Some IDEs may provide their own combinations. For example:
IntelliJ on macOS: Cmd+D. (Ctrl+D starts the debugger instead.)
IntelliJ on Windows: Ctrl+D.
Some IDEs may provide no way at all.
Some IDEs (e.g. online) don't support user input, and so readLine() will always return null.
Due to the confusion that this can cause, Kotlin 1.6 added a readln() function, which never returns null: instead, it throws a RuntimeException if end-of-file is reached, or on platforms such as Kotlin/JS which don't support user input in this way.
(That may make it slightly easier to write beginner programs, but IMHO it's merely turning a compile-time issue into a hidden run-time one, which seems like a backward step for a language as clear and safe as Kotlin…)
At the tcl try manpage, it has the following example:
try {
set f [open /some/file/name w]
} trap {POSIX EISDIR} {} {
puts "failed to open /some/file/name: it's a directory"
} trap {POSIX ENOENT} {} {
puts "failed to open /some/file/name: it doesn't exist"
}
That's great, it works, but how would I have found out that {POSIX ENOENT} is a possible trap pattern for open? The open manpage doesn't mention it. For a given arbitrary command in tcl, how do I find out what the possible errors are?
try {} trap {} is used when there is a specific error that needs to be trapped.
For a more general trap, use try {} on error {}.
try {
set fh [open myfile.txt w]
} on error {err res} {
puts "Error on open: $res"
}
There is also the catch command:
if { [catch {set fh [open myfile.txt w]}] } {
puts "error on open."
}
References: try catch
The various POSIX errors come from the OS, and you need to take a guess at the system call and look them up. For example, it's not a great reach to guess that the open command maps to the open() system call, and so it has the errors documented there. Some are vastly unlikely with Tcl (e.g., those relating to passing a bad buffer in, which is POSIX EFAULT) but we don't guarantee that the OS won't return them because the OS simply doesn't give that guarantee to us.
We ought to document the most likely ones from commands that touch the operating system, but at a high level:
the POSIX class ones are from the OS (e.g., reading a non-existent file is POSIX ENOENT), and
the TCL class ones are from Tcl's own internal code (e.g., from passing the wrong number of arguments to open, which gives you TCL WRONGARGS, or asking for too large a memory allocation, which gives you TCL MEMORY if Tcl manages to recover).
We're unlikely to exhaustively document all the possibilities (especially in the TCL class) since many are unlikely in correct code.
I'm debugging some code with an infinite loop, but it's difficult, because I can't get any log messages out. Here's a simplified case:
import Debug exposing (log)
f x =
let _ = log "Hello, world!" ()
in f x
If I run this at my Elm REPL like f (), it infinitely loops and never prints out "Hello, world!" as I expect it to.
I looked at the implementation of Debug.log (following it to Native.Debug.log), but it just seems to be calling process.stdout.write or console.log synchronously, so I'm surprised that I'm not seeing any output.
This is just a bug in the Elm REPL.
The Problem
I dove into the implementation of the Elm REPL. The relevant function is here: Eval.Code.run
This run function seems to be the function that executes a piece of code. It looks like each line of code is executed in a subprocess, via Elm.Utils. unwrappedRun. There are two problems with the way it runs it:
The stdout of the subprocess is not streamed; it's only returned once the whole subprocess is done. So as long as you're waiting for your code to finish evaluation, you won't see anything.
If you hit ctrl-c to end evaluation prematurely (which works fine, and returns you back to the Elm prompt), the Elm Repl ignores the stdout that is returned to it. Notice the pattern match for CommandFailed:
Left (Utils.CommandFailed _out err) ->
throwError err
The Utils.CommandFailed result helpfully includes the stdout (which is being bound to _out), but this code ignores it and just throws the error.
So basically this isn't anything that weird going on with the Elm compiler or runtime, just that the REPL isn't as good as it could be with respect to logged results.
The Workaround
As a workaround, in order to debug things like infinite loops, you can
put some test code in a new file, Scratch.elm, like x = f ()
compile the code with elm-make Scratch.elm --output scratch.js
run the code with node scratch.js
Then output will be streamed to your terminal.
Perl 6 Plain-Old-Documentation (perhaps Fancy-New-Documentation) has some features that allow it to construct documentation for things it sees, and the documentation shows up in the $=pod variable at runtime.
However, I was surprised when I couldn't read the docs when I'd made an error in the program text. Here I've left out a statement separator between two statements:
use v6;
BEGIN { put "BEGIN" }
INIT { put "INIT" }
CHECK { put "CHECK" }
"foo" "bar";
DOC INIT { put "DOC INIT" }
DOC BEGIN { put "DOC BEGIN" }
DOC CHECK { put "DOC CHECK" }
=begin pod
=head1 This is a title
This is a bit of pod
=end pod
When I run it with the --doc switch, the program syntax matters (and BEGIN runs):
$ perl6 --doc doc.p6
BEGIN
===SORRY!=== Error while compiling ...
Two terms in a row
------> "foo"⏏ "bar";
expecting any of:
infix
infix stopper
statement end
statement modifier
statement modifier loop
When I fix it, I get some warnings (so, perl6 is compiling) and the compilation-time phasers run:
BEGIN
DOC BEGIN
DOC CHECK
CHECK
WARNINGS for /Users/brian/Desktop/doc.p6:
Useless use of constant string "bar" in sink context (line 9)
Useless use of constant string "foo" in sink context (line 9)
INIT
DOC INIT
This is a title
This is a bit of pod
We already know this is a bit dangerous in Perl 5. A perl -c and a BEGIN block can run code. See How to check if a Perl script doesn't have any compilation errors?. I don't think this is any more dangerous than something we already know, but now it's happening at a time when I'm not explicitly asking something to compile program statements.
I haven't delved into the details of Perl 6 pod and why this might be necessary outside of declarator blocks and .WHY (a cool feature), but it seems like this can lead to trouble. Is there perhaps an external program that might extract the Pod? Or a way to do without the declarators unless the program will run?
Yes, the whole file has to be parsed, which in turn requires running BEGIN and use statements and such.
The Perl 6 language is designed for one-pass parsing from top to bottom, so that at any given point the parser understands what it is parsing based on what it has parsed so far.
Consider code like the following:
say "
=begin pod
Not POD, just a string!
";
If you'd just grep the file for POD statements without parsing all of it, it would misinterpret this piece of code.
I.e. you can't parse only the POD parts without parsing the normal Perl 6 code parts, because without parsing it all from top to bottom you can't know which is which.
PS: In theory, the Perl 6 designers could have accommodated POD-only parsing, by making it illegal for normal Perl 6 code to contain lines that look like they start a POD block. In this scenario, the above code snippet would be a syntax error when the whole file is parsed, because starting a line inside a string literal with =begin pod would be disallowed, so the --pod switch could rely on all lines that begin with =begin foo actually starting a POD block.
Such a restriction probably wouldn't be a major burden for normal Perl 6 code (after all, who needs to write =begin pod at the start of a line in a multi-line string literal), but note that one of the reasons for the one-pass top-to-bottom parsing architecture is to facilitate language extensibility via slangs.
E.g. CPAN modules could add support for users writing a single subroutine (or other lexical scope) in another language or DSL. (Implementing such modules isn't actually possible yet without hacking into Rakudo internals via NQP, but once the macro/slang design is complete, it will be).
The burden for disallowing lines that look like they start a POD block, would then be passed on to all those slang parsers.
You could always submit a feature request for Larry and the other Perl 6 designers to consider this, though.
Currently, to represent a newline in go programs, I use \n. For example:
package main
import "fmt"
func main() {
fmt.Printf("%d is %s \n", 'U', string(85))
}
... will yield 85 is U followed by a newline.
However, this doesn't seem all that cross-platform. Looking at other languages, PHP represents this with a global constant ( PHP_EOL ). Is \n the right way to represent newlines in a cross-platform specific manner in go / golang?
I got curious about this so decided to see what exactly is done by fmt.Println. http://golang.org/src/pkg/fmt/print.go
If you scroll to the very bottom, you'll see an if addnewline where \n is always used. I can't hardly speak for if this is the most "cross-platform" way of doing it, and go was originally tied to linux in the early days, but that's where it is for the std lib.
I was originally going to suggest just using fmt.Fprintln and this might still be valid as if the current functionality isn't appropriate, a bug could be filed and then the code would simply need to be compiled with the latest Go toolchain.
You can always use an OS specific file to declare certain constants. Just like _test.go files are only used when doing go test, the _[os].go are only included when building to that target platform.
Basically you'll need to add the following files:
- main.go
- main_darwin.go // Mac OSX
- main_windows.go // Windows
- main_linux.go // Linux
You can declare a LineBreak constant in each of the main_[os].go files and have your logic in main.go.
The contents of you files would look something like this:
main_darwin.go
package somepkg
const LineBreak = "\n"
main_linux.go
package somepkg
const LineBreak = "\n"
main_windows.go
package somepkg
const LineBreak = "\r\n"
and simply in your main.go file, write the code and refer to LineBreak
main.go
package main
import "fmt"
func main() {
fmt.Printf("%d is %s %s", 'U', string(85), LineBreak)
}
Having the OS determine what the newline character is happens in many contexts to be wrong. What you really want to know is what the "record" separator is and Go assumes that you as the programmer should know that.
Even if the binary runs on Windows, it may be consuming a file from a Unix OS.
Line endings are determined by what the source of the file or document said was a line ending, not the OS the binary is running in.
You can use os.PathSeparator
func main() {
var PS = fmt.Sprintf("%v", os.PathSeparator)
var LineBreak = "\n"
if PS != "/" {
LineBreak = "\r\n"
}
fmt.Printf("Line Break %v", LineBreak)
}
https://play.golang.com/p/UTnBbTJyL9c