Use Haskell like Prelude modules in a module in raku - haskell

I'm writing a drawing package with some parts, and I have operators and data types scattered througout. However I don't want the users to add the corresponding modules every time, since it would be quite messy, for instance I'd have a Point class, a Monoid role and a Style class
in different paths like this
unit module Package::Data::Monoid;
# $?FILE = lib/Package/Data/Monoid.pm6
role Monoid {...}
unit module Package::Data::Point;
# $?FILE = lib/Package/Data/Point.pm6
class Point {...}
unit module Package::Data::Style;
# $?FILE = lib/Package/Data/Style.pm6
class Style {...}
I would like to have a haskell like prelude in lib/Package/Prelude.pm6
with the effect that I can write such scripts
use Package::Prelude;
# I can use Point right away, Style etc...
instead of doing
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;
# I can too use point right away, but for users not knowing the
# inner workings it's too overwhelming
I've tried many things:
This version doesn't give me the right effect, I have to type
the whole path to point, i.e., Package::Data::Point...
unit module Package::Prelude;
# $?FILE = lib/Package/Prelude.pm6
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;
This version gives me the Point right away, but I get
problems with the operators and so on, also I would just like to
add automatically everything from the exported routines in the mentioned
example packages.
# $?FILE = lib/Package/Prelude.pm6
use Package::Data::Style;
use Package::Data::Point;
use Package::Data::Monoid;
sub EXPORT {
hash <Point> => Point
, <Style> => Style
, <mappend> => &mappend
...
}
Do you people know a better and quick way of getting such a prelude-like
file?

Using EXPORT is in the right direction. The key things to know are:
Imports are lexical
We can use introspection to obtain and access the symbols in the current lexical scope
So the recipe is:
use all the modules inside of EXPORT
Then extract all the imported symbols and return them as the result from EXPORT
As an example, I create a module Foo::Point, including an operator and a class:
unit module Foo::Point;
class Point is export {
has ($.x, $.y);
}
multi infix:<+>(Point $a, Point $b) is export {
Point.new(x => $a.x + $b.x, y => $a.y + $b.y)
}
And, just to demonstrate it can work with multiple modules, also a Foo::Monad:
unit module Foo::Monad;
class Monad is export {
method explain() { say "Just think of a burrito..." }
}
The goal is to make this work:
use Foo::Prelude;
say Point.new(x => 2, y => 4) + Point.new(x => 3, y => 5);
Monad.explain;
Which can be achieved by writing a Foo::Prelude that contains:
sub EXPORT() {
{
use Foo::Point;
use Foo::Monad;
return ::.pairs.grep(*.key ne '$_').Map;
}
}
There's a few oddities in here to explain:
A sub has implicit declarations of $_, $/, and $!. Exporting these would result in a compile-time symbol clash error when the module is use'd. A block only has an implicit $_. Thus we make our life easier with a nested bare block.
The grep is to make sure we don't export our implicitly declared $_ symbol (thanks to the nested block, it's the only one we have to care about).
:: is a way to reference the current scope (etymology: :: is the package separator). ::.pairs thus obtains Pair objects for each symbol in the current scope.
There's a speculated re-export mechanism that may appear in a future Raku language release that would eliminate the need for this bit of boilerplate.

Related

IBM Doors DXL: can't iterate over objects in module

I have a rather peculiar problem with IBM Doors, using its DXL language:
I CAN get a variable to the module I want to access:
our_mod = module "<path_including_filename_of_module>"
I can NOT perform any of the usual functions pertaining to modules on that variable, e.g.:
name (our_mod) //or entering the string consisting of path + filename directly)
it gives me the error output: "incorrect arguments for fucntion (name)"
BUT, if I search through the folder containing the module, I can grab it via its filename:
Item x
Item my_module
for x in my_folder do
{
if (name(x) == "<filename>")
{
my_module = x
}
}
THEN I can perform name(my_module) or type (my_module):
returns the filename and "Formal" as expected
But even if I get the module that way, I still can NOT iterate over the objects inside that module like with
Object o
for o in my_module do // ...in all my_module... does not work either, same error msg
{
//Do what I came to do...
}
It just gives me the error message "incorrect arguments for (do)"
If anybody had any idea whatsoever as to what might be causing this, would be much obliged.
thanks and regards
There are several data types in DXL that have something to do with modules, all of them have different access functions (perms). E.g. variables of type Item are good for iterating over "everything in a folder or project". If you want to iterate over objects, you need a variable of type Module. As you already found out, the perm "module (string)" does NOT return data of type Module. It returns either a variable of type bool or of type ModName_ (which is a module reference, not a module), depending on the data type where you assign the result. For details, see e.g. the perms list on Tony Goodman's page at http://www.smartdxl.com/downloads/undoc31.html.
In DXL, make sure that you ALWAYS declare variables with a type, never use Auto-Declare if you want to keep your sanity (if you say print our_mod in your upper example you will find that you got a bool, which of course has neither a name nor a type).
For getting a variable of type Module, you first need to open the module (like in real life :) :)). You can open it using edit, share or read. E.g. like this
Module m = read ("/path/to/my_mod", false /* display */, true /* load standard view */)
if null m then error "could not open the module"
Object o
for o in entire m do {print o."Absolute Number" ""}
close m

Perl 6 - Is it possible to create an attribute trait that set a meta-attribute?

I try to create an attribute trait. The use case is to mark some attributes of a class as "crudable" in the context of an objects-to-documents-mapping while other are not.
role crud {
has Bool $.crud is default(True);
}
multi trait_mod:<is>(Attribute $a, crud, $arg) {
$a.container.VAR does crud($arg);
}
class Foo {
has $.bar is rw;
# Provide an extra nested information
has $.baz is rw is crud(True);
}
By reading and adapting some example code, I managed to get something that seems to do what I want. Here is a snippet with test case.
When I instantiate a new Foo object and set the $.bar attribute (that is not crud), it looks like that:
.Foo #0
├ $.bar is rw = 123456789
└ $.baz is rw = .Scalar+{crud} #1
└ $.crud +{crud} = True
What I understand from this is that the $.baz attribute got what I call a meta-attribute that is independent from its potential value.
It looks good to me (if I understood correctly what I did here and that my traits use is not a dirty hack). It is possible to reach $foo.baz.crud that is True. Though, I don't understand very well what .Scalar+{crud} means, and if I can set something there and how.
When I try to set the $.baz instance attribute, this error is returned:
Cannot modify an immutable Scalar+{crud} (Scalar+{crud}.new(crud => Bool::True))
in block <unit> at t/08-attribute-trait.t line 30
Note: This is the closest thing to a working solution I managed to get. I don't need different crud settings for different instances of instantiated Foo classes.
I never want to change the value of the boolean, in fact, once the object instantiated, just providing it to attributes with is crud. I am not even interested to pass a True or False value as an argument: if it would be possible to just set the boolean trait attribute to True by default, it would be enough. I didn't manage to do this though, like:
multi trait_mod:<is>(Attribute $a, :$crud!) {
# Something like this
$a.container.VAR does set-crud;
}
class Foo {
has $.bar is rw;
has $.baz is rw is crud;
}
Am I trying to do something impossible? How could I adapt this code to achieve this use case?
There are several things going on here. First of all, the signature of the trait_mod looks to be wrong. Secondly, there appears to be a bad interaction when the name of a trait is the same as an existing role. I believe this should be an NYI exception, but apparently it either goes wrong in parsing, or it goes wrong in trying to produce the error message.
Anyways, I think this is what you want:
role CRUD {}; # since CRUD is used as an acronym, I chose to use uppercase here
multi trait_mod:<is>(Attribute:D $a, :$crud!) { # note required named attribute!
$a.^mixin: CRUD if $crud; # mixin the CRUD role if a True value was given
}
class A {
has $.a is crud(False); # too bad "is !crud" is invalid syntax
has $.b is crud;
}
say "$_.name(): { $_ ~~ CRUD }" for A.^attributes; # $!a: False, $!b: True
Hope this helps.

How to get protobuf.js to output enum strings instead of integers

I'm using the latest protobuf.js with Node.js 4.4.5.
I currently struggle to get protobuf.js to output the string definitions of enums instead of integers. I tried several suggestions, but none of them worked:
https://github.com/dcodeIO/ProtoBuf.js/issues/97
https://github.com/dcodeIO/protobuf.js/issues/349
I guess it's because of API changes in protobuf.js for the first one. For the second one, I can use the suggested solution partially, but if the message is nested within other messages, the builder seems to fall back to using the integer values, although the string values have been explicitly set.
Ideally, I'd like to overwrite the function which is used for producing the enum values, but I have a hard time finding the correct one with the debugger. Or is there a better way to achieve this for deeply nested objects?
The generated JS code from protoc has a map in one direction only e.g.
proto.foo.Bar.Myenum = {
HEY: 0,
HO: 1
};
Rationale for this is here but you have to the reverse lookup in your own JS code. There are lots of easy solutions for this. I used the one at https://stackoverflow.com/a/59360329/449347 i.e.
Generic reverse mapper function ...
export function getKey(map, val) {
return Object.keys(map).find(key => map[key] === val);
}
UT ...
import { Bar } from "js/proto/bar_pb";
expect(getKey(proto.foo.Bar.Myenum, 0)).toEqual("HEY");
expect(getKey(proto.foo.Bar.Myenum, 1)).toEqual("HO");
expect(getKey(proto.foo.Bar.Myenum, 99)).toBeUndefined();

Array access not allowed on OpenFL movieclips

UDATED
How do I go about this?
I got this from Main.hx:
function onMouseOver(e:MouseEvent){
if(Std.is(e.currentTarget, MovieClip)){
initializer (cast e.currentTarget,["scaleX",1.5,"scaleY",1.5])
}
}
Then this is the pointed function in my Animation Class
//here if i set mc:Dynamic everything goes great! but when this one
function initializer(mc:MovieClip, vars:Array<Dynamic>){
var varsLength:Int = Math.round(vars.length/2);
for(m in 0...varsLength){
ini[m] = mc[vars[2*m]];
}
}
then when i compile it, an error appears:
Error: Array access is not allowed in flash.display.MovieClip
How do I resolve this?
EDIT:
vars: are properties of the MovieClip, for example when I pass these parameters:
initializer (mcClip1,["scaleX",1.5,"scaleY",1.5])
so:
vars = ["scaleX",1.5,"scaleY",1.5]
and:
ini[m] will store "scaleX" and "scaleY"`
X-Ref: https://groups.google.com/forum/#!topic/haxelang/_hkyt__Rrzw
In AS3, you can access fields of an object via their String name using [] (array access). This is called Reflection.
In Haxe, Reflection works differently - you need to make use of the Reflect API.
It's considered bad practice - it's not type-safe, which means the compiler can do very little to help you with error messages, and it's quite slow as well. This is why the usage makes it very explicit that Reflection is actually going on (while in AS3, this fact is somewhat hidden). Consider if there are other ways of solving this problem that don't require Reflection.
Now, to get back to your example, here's what it would look like in Haxe:
function onMouseOver(e:MouseEvent){
if (Std.is(e.currentTarget, MovieClip)) {
initializer(cast e.currentTarget, ["scaleX", 1.5, "scaleY", 1.5])
}
}
function initializer(mc:MovieClip, vars:Array<Dynamic>) {
for (m in 0...Std.int(vars.length / 2)) {
ini[m] = Reflect.getProperty(mc, vars[2*m]);
}
}
Btw, your loop was running for too long since you only use half of the values in the array - if you don't divide it by two like I did, you'll end up with [scaleX, scaleY, null, null] instead of the desired [scaleX, scaleY].

Puppet: how can i pass value from inherited class to base class?

How can I pass value from inherited class to base class using puppet?
You can see below a simplified code for my trials.
class executor::app($base_dir = "/usr/local",
$run_command = undef,
$prefix_naming = undef) {
}
class app1(
$base_dir = ::app1::params::base_dir,
$prefix_naming = "reader",
$run_command = " ") inherits executor::app{
}
OK, for starters lets assume you have these classes in module format. If not, then that should be the first order of business.
Second, avoid inheritance. There is almost always a better way to do it. Especially don't inherit across modules. About the only time I can think it's useful is for defaulting class parameters.
The base_dir on class app1 will not get the default unless the class inherits cea::params::base_dir (leading :: not needed). Again, across modules shouldn't be done. app1::params much better -- or just put in a sane default and eliminate the need to inherit parameters all together.
For your actual question, if you want to get a variable in another class you can just reference it. Keep in mind that puppet doesn't guarantee compile order so you should tell it to evaluate the other class first:
class executor::app {
Class['app1'] -> Class['executor::app']
$other_app_var = $app1::base_dir
}
Or throw this data in hiera and look up the value.

Resources