It looks like maxpairs doesn't like to be called on a list with undefined values:
> my #foo; #foo[2] = 4; say #foo.maxpairs;
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
in block <unit> at <unknown file> line 1
(2 => 4)
max doesn't have the same issue and seems to simply ignore undefined values:
> my #foo; #foo[2] = 4; say #foo.max;
4
The same error does occur with:
> my #foo; #foo[2] = 4; say #foo.pairs.max(*.value)
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful.
in block <unit> at <unknown file> line 1
2 => 4
So it appears that undefined values are only ignored when using max without a filter parameter.
Is this a bug?
Since this looks like a bug, I've fixed it with
https://github.com/rakudo/rakudo/commit/7bf7a2c6f83a57713c
Which also takes care of "minpairs".
Related
Here learning my way around Raku (neé Perl 6), very nice all around. But I sorely miss the magic <> from Perl 5, where you can just:
my $x = <>;
print $x;
while(<>) {
print join(':', split);
}
(read next input line into $x, loop over the rest; input is from the files named as input or standard input if no file given). The "Perl 5 to 6" tutorials/migration guides/... just talk about slurping the whole file, or opening individual files by name. No magic "take input from named files in sequence" I can find.
I want the magic back!
The functionality you're looking for largely exists. This script:
my $x = get();
say "First: $x";
for lines() {
.say
}
Given these inputs files:
$ cat foo
foo line 1
foo line 2
$ cat bar
bar line 1
bar line 2
Will, when invoked as:
raku script.p6 foo bar
Produce the output:
First: foo line 1
foo line 2
bar line 1
bar line 2
It will also take output from $*IN if there aren't files. The only thing that doesn't exist is a single replacement for <>, since that would depend on wantarray-like functionality, which is incompatible with multiple dispatch (and Raku considers multiple dispatch is far more useful).
The zero-arg candidates for get and lines are implemented in terms of $*ARGFILES, a file handle that provides the functionality of taking the files from the argument list or from $*IN - meaning one can pass it to any code that expects a file handle.
Enough magic for you?
sub MAIN( Str $file where *.IO.f )
{
.say for $file.IO.lines.map: *.comb.join(':');
}
In this script:
role Capturer {
method capturing(::CLASS:D: $ ) {
say "Working with ", $?CLASS, " that holds ", $.gist;
}
}
( <1 2 3 4> but Capturer ).capturing();
A arg-less method is defined, capturing, but if I call it this way, I get:
Too few positionals passed; expected 2 arguments but got 1
in method capturing at captured-class.p6 line 4
in block <unit> at captured-class.p6 line 10
I can fix that giving it a dummy argument
Too few positionals passed; expected 2 arguments but got 1
in method capturing at captured-class.p6 line 4
in block <unit> at captured-class.p6 line 10
Which then returns:
Working with (List+{Capturer}) that holds (1 2 3 4)
Any idea of what kind of argument is waiting for there?
Any argument really, because the method you defined is NOT argumentless:
method capturing(::CLASS:D: $ )
^^^
that defines a single, nameless positional argument. Which, without any type specification, will accept an Any. So the answer to your question:
Any idea of what kind of argument is waiting for there?
already contains the answer: Any value :-)
I am trying to run following very simple code:
open Str
print (Str.first_chars "testing" 0)
However, it is giving following error:
$ ocaml testing2.ml
File "testing2.ml", line 2, characters 0-5:
Error: Syntax error
There are no further details in the error message.
Same error with print_endline also; or even if no print command is there. Hence, the error is in part: Str.first_chars "testing" 0
Documentation about above function from here is as follows:
val first_chars : string -> int -> string
first_chars s n returns the first n characters of s. This is the same
function as Str.string_before.
Adding ; or ;; at end of second statement does not make any difference.
What is the correct syntax for above code.
Edit:
With following code as suggested by #EvgeniiLepikhin:
open Str
let () =
print_endline (Str.first_chars "testing" 0)
Error is:
File "testing2.ml", line 1:
Error: Reference to undefined global `Str'
And with this code:
open Str;;
print_endline (Str.first_chars "testing" 0)
Error is:
File "testing2.ml", line 1:
Error: Reference to undefined global `Str'
With just print command (instead of print_endline) in above code, the error is:
File "testing2.ml", line 2, characters 0-5:
Error: Unbound value print
Note, my Ocaml version is:
$ ocaml -version
The OCaml toplevel, version 4.02.3
I think Str should be built-in, since opam is not finding it:
$ opam install Str
[ERROR] No package named Str found.
I also tried following code as suggested in comments by #glennsl:
#use "topfind"
#require "str"
print (Str.first_chars "testing" 0)
But this also give same simple syntax error.
An OCaml program is a list of definitions, which are evaluated in order. You can define values, modules, classes, exceptions, as well as types, module types, class types. But let's focus on values so far.
In OCaml, there are no statements, commands, or instructions. It is a functional programming language, where everything is an expression, and when an expression is evaluated it produces a value. The value could be bound to a variable so that it could be referenced later.
The print_endline function takes a value of type string, outputs it to the standard output channel and returns a value of type unit. Type unit has only one value called unit, which could be constructed using the () expression. For example, print_endline "hello, world" is an expression that produces this value. We can't just throw an expression in a file and hope that it will be compiled, as an expression is not a definition. The definition syntax is simple,
let <pattern> = <expr>
where is either a variable or a data constructor, which will match with the structure of the value that is produced by <expr> and possibly bind variable, that are occurring in the pattern, e.g., the following are definitions
let x = 7 * 8
let 4 = 2 * 2
let [x; y; z] = [1; 2; 3]
let (hello, world) = "hello", "world"
let () = print_endline "hello, world"
You may notice, that the result of the print_endline "hello, world" expression is not bound to any variable, but instead is matched with the unit value (), which could be seen (and indeed looks like) an empty tuple. You can write also
let x = print_endline "hello, world"
or even
let _ = print_endline "hello, world"
But it is always better to be explicit on the left-hand side of a definition in what you're expecting.
So, now the well-formed program of ours should look like this
open Str
let () =
print_endline (Str.first_chars "testing" 0)
We will use ocamlbuild to compile and run our program. The str module is not a part of the standard library so we have to tell ocamlbuild that we're going to use it. We need to create a new folder and put our program into a file named example.ml, then we can compile it using the following command
ocamlbuild -pkg str example.native --
The ocamlbuild tool will infer from the suffix native what is your goal (in this case it is to build a native code application). The -- means run the built application as soon as it is compiled. The above program will print nothing, of course, here is an example of a program that will print some greeting message, before printing the first zero characters of the testing string,
open Str
let () =
print_endline "The first 0 chars of 'testing' are:";
print_endline (Str.first_chars "testing" 0)
and here is how it works
$ ocamlbuild -package str example.native --
Finished, 4 targets (4 cached) in 00:00:00.
The first 0 chars of 'testing' are:
Also, instead of compiling your program and running the resulting application, you can interpret your the example.ml file directly, using the ocaml toplevel tool, which provides an interactive interpreter. You still need to load the str library into the toplevel, as it is not a part of the standard library which is pre-linked in it, here is the correct invocation
ocaml str.cma example.ml
You should add ;; after "open Str":
open Str;;
print (Str.first_chars "testing" 0)
Another option is to declare code block:
open Str
let () =
print (Str.first_chars "testing" 0)
Why isn't the value of a variable with := binding exported?
$ cat myModule.pm6
our $a is export = 42;
our $b is export := $a;
$ cat program.p6
use myModule;
say $a;
say $b;
$ perl6 program.p6
42
(Any) # Why?
An our-scoped variable is really just a lexical variable (like my) that - instead of having a Scalar freshly created per scope - is initialized by being bound to a symbol of that name in the Stash of the current package. So effectively, this:
our $foo;
Is doing this:
my $foo := $?PACKAGE.WHO<$foo>;
And so:
our $foo = 42;
Is doing this:
(my $foo := $?PACKAGE.WHO<$foo>) = 42;
Rebinding the symbol thus means it's no longer associated with the Scalar container stored in the Stash.
Exporting an our-scoped variable exports the Scalar container from the stash that the variable is bound to at scope entry time. Thus the assignment assigns into that exported Scalar container. By contrast, binding replaces the lexical with something entirely different and unrelated to what was exported.
This is why you aren't allowed to export a my-scoped variable: a fresh Scalar is bound every scope entry, but exportation is a compile-time thing, so there would be no way to ever modify the thing that was exported.
Which one is proper way of using variable with or without dollar sign? I thought that variable (without $) is used only during variable declaration (similar to Bash):
set var 10
In all other cases when variable is referred or used (but not declared) the proper syntax is $variable (with $):
set newVar $var
puts $var
puts $newVar
But then I found code where it is interchanged and seems that this code is working:
# using argv
if {[array exists argv]} {
puts "argv IS ARRAY"
} else {
puts "argv IS NOT AN ARRAY"
}
# using $argv
if {[array exists $argv]} {
puts "\$argv IS ARRAY"
} else {
puts "\$argv IS NOT AN ARRAY"
}
# using argv
if {[string is list argv]} {
puts "argv IS LIST"
} else {
puts "argv IS NOT LIST"
}
# using $argv
if {[string is list $argv]} {
puts "\$argv IS LIST"
} else {
puts "\$argv IS NOT LIST"
}
Output:
argv IS NOT AN ARRAY
$argv IS NOT AN ARRAY
argv IS LIST
$argv IS LIST
Edit in reply to #glenn jackman:
Your reply pointed me to further research and I've found that TCL is capable doing some sort of "self modifying code" or whatever is correct name e.g.:
% set variableName "x"
x
% puts $x
can't read "x": no such variable
% set $variableName "abc"
abc
% puts $x
abc
% puts [set $variableName]
abc
%
%
%
%
%
%
% set x "def"
def
% puts $x
def
% puts [set $variableName]
def
%
Now your answer bring some light to problem, but one question remains. This is excerpt from documentation:
set varName ?value?
array exists arrayName
Documentation says that both functions expect variable name (not value) in other words it expect variable instead of $variable. So I assume (based on above self modifying code) that when I pass $variable instead of variable the variable substitution took place (exactly the same as code above). But what if $variable contains something that is not a list neither array (my arguments during testing was: param0 param1 "param 2" param3). From this point of view the output that says $argv IS LIST is wrong. What am I missing here?
Edit in reply to #schlenk:
Finally I (hope) understand the problematic. I've found great article about TCL, which explain (not just) this problematic. Let me pinpoint a few wise statement from this article:
In Tcl what a string represents is up to the command that's
manipulating it.
Everything is a command in Tcl - as you can see there is no
assignment operator.
if is a command, with two arguments.
The command name is not a special type but just a string.
Also following SO answer confirms this statement:
"In Tcl, values don't have a type... they question is whether they can be used as a given type."
The command string is integer $a means:
"Can I use the value in $a as an integer"
NOT
"Is the value in $a an integer"
"Every integer is also a valid list (of one element)... so it can be
used as either and both string is commands will return true (as will
several others for an integer)."
I believe the same applies also for string is list command:
% set abc "asdasd"
asdasd
% string is list $abc
1
% string is alnum $abc
1
string is list returns 1 because $abc is string and also it is one element list etc. In most tutorials there are said that following snippet is the proper way of declaring and working with lists:
% set list1 { 1 2 3 }
% lindex $list1 end-1
2
But when everything in TCL is string the following is also working in my experience (if I am wrong correct me please).
% set list2 "1 2 3"
1 2 3
% lindex $list2 end-1
2
It depends on the command. Some Tcl commands require a variable name as a parameter, if they need to modify the contents of the variable. Some are:
set
foreach
lappend
incr
Most but certainly not all commands want to take a variable's value.
You'll need to check the documentation for the relevant commands to see if the parameters include "varName" (or "dictionaryVariable"), or if the parameters are named as "string", "list", etc
An example using info exists which takes a varName argument:
% set argv {foo bar baz}
foo bar baz
% info exists argv ;# yes the variable "argv" exists
1
% info exists $argv ;# no variable named "foo bar baz"
0
% set {foo bar baz} "a value" ;# create a variable named "foo bar baz"
a value
% info exists $argv ;# so now that variable exists
1
The important thing to know is that $x in Tcl is just syntactical sugar for the command set x. So you can translate any $x in Tcl code into [set x] in the same place to see what really happens.
The other important thing to consider is immutable values. Tcl values are immutable, so you cannot change them. You can just create a new changed value. But you can change the value stored inside a variable.
This is where the difference between commands taking a variable name and those that take a value comes in. If a command wants to change the value stored in a variable, it takes a variable name. Examples are lappend, lset, append and so on. Other commands return a new value and take a value as argument, examples include lsort, lsearch, lindex.
Another important point is the fact that you do not really have a list type. You have strings that look like lists. So that is what Tcl's string is list tests. This has some consequences, e.g. you cannot always decide if you have a string literal or a one item list, as it is often the same. Example given:
% set maybe_list a
% string is list $maybe_list
1
Combine that with Tcls nearly unrestricted names for variables, as already demonstracted by Glenn and you can get really confused. For example, these are all valid Tcl variable names, you just cannot use all of them with the $ shortcut:
% set "" 1 ;# variable name is the empty string
1
% puts [set ""]
% set " " 1 ;# variable name is just whitespace
1
% puts [set " "]
1
% set {this is a list as variable name} 1 ;# a variable with a list name
1
% puts [set {this is a list as variable name}]
1
% set Δx 1
1
% incr Δx
2
% puts [set Δx]
2