Why don't new operator definitions persist in the Perl 6 REPL? - operators

I was having issues experimenting with defining operators on the Perl 6 REPL, and noticed that they do work, but only when used on the same line as they are defined. Why is this the case?
> sub postfix:<!>(Int $x where { $x >= 0 }) { [*] 1..$x }; 6!;
720
> 6!;
===SORRY!=== Error while compiling:
Negation metaoperator not followed by valid infix
------> 6!⏏;
expecting any of:
infix
infix stopper

It's a bug.
See bug reports Perl6 REPL forgets the definition of ... and REPL issue defining new operator... for more details.

Related

Alternative to Perl's <> in Raku?

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(':');
}

Why syntax error in this very simple print command

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)

Cannot import Perl5 module using Inline::Perl5 into Perl6

I'm trying to import a Perl5 module I really like https://metacpan.org/pod/Data::Printer
using advice from the manual page https://modules.perl6.org/dist/Inline::Perl5:cpan:NINE
using a very simple script
use Inline::Perl5;
my $p5 = Inline::Perl5.new;
$p5.use('Data::Printer');
but then I get this error:
Unsupported type NativeCall::Types::Pointer<94774650480224> in p5_to_p6
in method p5_to_p6_type at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 298
in method unpack_return_values at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 375
in method invoke at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 446
in method import at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 776
in method use at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 898
in block <unit> at inline_perl5.p6 line 4
what is going wrong here? How can I import this perl5 module into perl6? I would also be happy if there is a similar way to get the colored/tabbed output in Perl6 like I would get from Data::Printer because I can't find it.
EDIT: This is solved here: how to load Perl5's Data::Printer in Perl6?
I think you stumbled on a bug in Inline::Perl5 that seems to happen for the Data::Printer Perl 5 module, so I would suggest you open an issue for it at https://github.com/niner/Inline-Perl5/issues .
Meanwhile, the syntax has become much simpler. Once you have Inline::Perl5 installed, you only need to add the :from<Perl5> adverb to load a module from Perl 5:
use Data::Printer:from<Perl5>;
Unfortunately, at this moment that creates the same error that you already described:
===SORRY!===
Unsupported type NativeCall::Types::Pointer<140393737675456> in p5_to_p6
So I don't think there is a solution this that wouldn't require an upgrade of either Inline::Perl5 or Rakudo Perl 6.
From the github page, https://github.com/niner/Inline-Perl5/issues/128
> perl6 -Ilib -e 'use Data::Printer:from<Perl5>; my #a = 1, 2, [3, 4, ${a => 1}]; p #a'
[
[0] 1,
[1] 2,
[2] [
[0] 3,
[1] 4,
[2] {
a 1
} (tied to Perl6::Hash)
]
]
I'm not particularly happy with this though. This is much more complicated than perl5 would have been. One of the main points of using Perl6 over Perl5 is simpler use and syntax. This isn't it. The 'Inline::Perl5' module should be able to be loaded within the script like every other module, not as an option at the command line.

What is the perl6 equivalent of #INC, please?

I go
export PERL6LIB="/GitHub/perl6-Units/lib"
and then
echo $PERL6LIB
/GitHub/perl6-Units/lib
But when I run perl6 t/01-basic.t
use v6;
use Test;
plan 3;
lives-ok {
use Units <m>;
ok #Units::UNITS.elems > 0;
ok (0m).defined;
}
done-testing;
I still get an error
===SORRY!===
Could not find Units at line 8 in:
/Users/--me--/.perl6
/usr/local/Cellar/rakudo-star/2018.01/share/perl6/site
/usr/local/Cellar/rakudo-star/2018.01/share/perl6/vendor
/usr/local/Cellar/rakudo-star/2018.01/share/perl6
CompUnit::Repository::AbsolutePath<140707489084448>
CompUnit::Repository::NQP<140707463117264>
CompUnit::Repository::Perl5<140707463117304>
In Perl 5 I would have used print "#INC"; to see what paths are searched for the lib before the error is thrown. Using say flat $*REPO.repo-chain.map(*.loaded); either is before it loads or after it throws the exception.
Any help would be much appreciated - or maybe a hint on what to put in ~/.perl6 as I can't get a symlink to work either.
The error message itself is telling you what the library paths available are. You are failing to print them because you are expecting a run time action ( say ) to take place before a compile time error -- you could print out $*REPO at compile time, but again the exception is already showing you what you wanted.
$ PERL6LIB="/GitHub/perl6-Units/lib" perl6 -e 'BEGIN say $*REPO.repo-chain; use Foo;'
(file#/GitHub/perl6-Units/lib inst#/Users/ugexe/.perl6 inst#/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/site inst#/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/vendor inst#/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6 ap# nqp# perl5#)
===SORRY!===
Could not find Foo at line 1 in:
/GitHub/perl6-Units/lib
/Users/ugexe/.perl6
/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/site
/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/vendor
/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6
CompUnit::Repository::AbsolutePath<140337382425072>
CompUnit::Repository::NQP<140337350057496>
CompUnit::Repository::Perl5<140337350057536>
You can see /GitHub/perl6-Units/lib is showing up in the available paths, which is unlike your example. I'd question if your shell/env is actually setup correctly.

Vim: Writing function skeleton

When writing new functions with Vim I always seem to have to do a bit of "manual" work.
x = Cursor position
If I start typing a function and insert a couple of curly braces and the end
function Apples() {x}
Then hit Enter, it obviously looks like this
function Apples() {
x}
Which results in me having to ESC,O in order to shift the closing curlybrace down.
While this may seem like a trivial matter, doing this over the last 5 months is getting bothersome, and I know there are plenty like me out there who knows there should be an elegant solution to this. I am open to plugin-suggestions.
You can use a simple mapping like this one (there are dozens of variants floating around SO and the web):
inoremap {} {<CR>}<C-o>O
You can also search www.vim.org for a dedicated plugin.
But I strongly recommend you to try a snippet-expansion plugin like Snipmate or UltiSnips. Both plugins follow the same model but they have slightly different snippet syntaxes and features. It works like that:
you type a trigger:
fun
you hit <Tab> and you get the following with function_name in select mode:
function [function_name]() {
}
you type your desired name:
function Apples|() {
}
you hit <Tab> to place the cursor between the parentheses:
function Apples(|) {
}
you hit <Tab> again to place the cursor on the line below with the correct indentation:
function Apples() {
|
}
With lh-bracket (in C or C++ mode), when you hit enter whilst in between two brackets, the newlines you are expecting are inserted.
The idea is to test for: getline(".")[col(".")-2:col(".")-1]=="{}" and execute/insert "\<cr>\<esc>O" when the condition is true, or "\<cr>" otherwise.
Within lh-bracket, I have the following into a C-ftplugin:
call lh#brackets#enrich_imap('<cr>',
\ {'condition': 'getline(".")[col(".")-2:col(".")-1]=="{}"',
\ 'action': 'Cpp_Add2NewLinesBetweenBrackets()'},
\ 1,
\ '\<cr\>'
\ )
function! Cpp_Add2NewLinesBetweenBrackets()
return "\<cr>\<esc>O"
endfunction
I guess (code not tested) it would (*) translate into:
" put it into ftplugin/{yourfiltetype, javascript?}.vim
inoremap <buffer> <silent> <expr> <cr> s:SmartCR()
function s:SmartCR()
return getline(".")[col(".")-2:col(".")-1]=="{}"
\ ? "\<cr>\<esc>O"
\ : "\<cr>"
endfunction
(*) Actually, lh#brackets#enrich_imap does a few other things (the mapping is compatible with LaTeXSuite's IMAP.vim presence ; the mapping can be toggled on/off along with all the other mappings from lh-brackets)