Hylang Map Destructuring - destructuring

Does hylang support map destructuring like in clojure?
For example: https://gist.github.com/john2x/e1dca953548bfdfb9844#maps

Hy does not have mapping destructuring built in, though Python's iterable destructuring does work in Hy.
You can destructure maps in Python this way using list comprehensions, but it's limited, for example,
>>> dict(a=1, b=2, c=3)
{'a': 1, 'b': 2, 'c': 3}
>>> a, b, c = [_[k] for k in ['a', 'b', 'c']]
>>> a
1
>>> b
2
>>> c
3
This gets awkward when the dicts are nested in something, but sometimes this is good enough. It would be fairly easy to make a macro for this idiom in Hy.
I've also worked on a hy.contrib.destructure module. It still hasn't been merged (not really finished), but the mapping destructuring part works. You could try using that if you need to work with deeply nested data. The synatx is similar to Clojure. The macros have docstrings and the unit tests have examples.
UPDATE
peaceamongworlds polished up my old destructuring branch. It was merged into master on January 31, 2021.
See the docs for the new module here.
Python will also have the ability to destructure mappings in its match/case statements, as of version 3.10.

Related

Why can't a range of char be collected?

I'm trying to generate a vector containing lowercase ASCII characters. This more convoluted approach works:
let ascii_lowercase = (b'a'..=b'z').map(|b| b as char).collect::<Vec<char>>();
But this more straightforward one, which I came up with in the first place, does not:
let ascii_lowercase = ('a'..='z').collect::<Vec<char>>();
The error is:
error[E0599]: no method named `collect` found for type `std::ops::RangeInclusive<char>` in the current scope
--> src/main.rs:2:39
|
2 | let ascii_lowercase = ('a'..='z').collect::<Vec<char>>();
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied:
`std::ops::RangeInclusive<char> : std::iter::Iterator`
`&mut std::ops::RangeInclusive<char> : std::iter::Iterator`
Which is weird, because as far as I understand, there is a blanket implementation of Iterator for RangeInclusive.
Is it impossible to use a range of chars as an iterator? If so, why? If not, what am I doing wrong? I'm using stable Rust 2018 1.31.1.
EDIT 2020-07-17: since Rust 1.45.0, the trait Step is implemented for char, making Range<char> (and some other char ranges) work as an iterator. The code in the question now compiles without problem!
Old answer below.
The expression b'a'..=b'z' has the type RangeInclusive<u8> (see on Playground) because the expression b'a' has the type u8: that's what the b in front of the character literal is for. On the other hand, the expression 'a'..='z' (without the bs) has the type RangeInclusive<char>.
[...] there is a blanket implementation of Iterator for RangeInclusive.
For one, this is not what we call "blanket implementation" (this is when the impl block is for T or for &T (or similar) with T being a generic type). But yes, there is an impl. But let's take a closer look:
impl<A> Iterator for RangeInclusive<A>
where
A: Step, // <--- important
The A: Step bound is important. As you can see in the documentation for Step, this trait is implemented for all primitive integer types, but not for char. This means that there is no clear "add one" operation on characters. Yes, you could define it to be the next valid Unicode codepoint, but the Rust developers probably decided against that for a good reason.
As a consequence, RangeInclusive<char> does not implement Iterator.
So your solution is already a good one. I would probably write this:
(b'a'..=b'z').map(char::from).collect::<Vec<_>>()
The only real advantage is that in this version, char doesn't appear twice.
The problem was that the iteration capabilities of range types depend on the Step trait (see extended answer).
However, starting from Rust 1.45, char also implements Step (PR 72413), which means that the code in the question now works!
let ascii_lowercase: Vec<char> = ('a'..='h').collect();
assert_eq!(
ascii_lowercase,
vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
);

How do I organize complex data in julia

I decided to try julia a few days ago and tried to translate one of my python projects to julia. I understand that using the type system is crucial for good performance. However, I have something like this in python:
class Phonon(object):
# it has an attribute called D which looks like
# D = {'on_site': [D00, D11, D22, D33 ...], 'lead':{'l': [Dl00, Dl01, Dl11], 'r': [Dr00, Dr01, Dr11]},'couple': [D01, D12, D23 ...], 'lead_center':{'l': Dlcl, 'r': Dlcr}}
# all D00, D11, D22 matrices are numpy arrays
If I translate this into julia, it would be:
type Phonon:
D::Dict{ASCIIString, Any}
end
It seems that compiler cannot get much infomation about what phonons are. So my question is: How do julia people organize their complex data?
if i understood you properly, you may want something like this:
type PhononDict{T<:Number}
on_site::Vector{Matrix{T}}
lead::Dict{ASCIIString, Vector{Matrix{T}}}
couple::Vector{Matrix{T}}
lead_center::Dict{ASCIIString, Matrix{T}}
end
i assumed that the element type of your numpy array <: Number, you can adjust it to something like T<:Union{Int64, Float64} instead.
the key problem here is lead::Dict, so D::Dict{ASCIIString, Any}:
julia> typejoin(Array, Dict)
Any
i suggest to change D into a composite type and then you can pass more info to compiler. more information concerning parametric types.

Returning multiple values in Ruby, to be used to call a function

Is it possible to return multiple values from a function?
I want to pass the return values into another function, and I wonder if I can avoid having to explode the array into multiple values
My problem?
I am upgrading Capybara for my project, and I realized, thanks to CSS 'contains' selector & upgrade of Capybara, that the statement below will no longer work
has_selector?(:css, "#rightCol:contains(\"#{page_name}\")")
I want to get it working with minimum effort (there are a lot of such cases), So I came up with the idea of using Nokogiri to convert the css to xpath. I wanted to write it so that the above function can become
has_selector? xpath(:css, "#rightCol:contains(\"#{page_name}\")")
But since xpath has to return an array, I need to actually write this
has_selector?(*xpath(:css, "#rightCol:contains(\"#{page_name}\")"))
Is there a way to get the former behavior?
It can be assumed that right now xpath func is like the below, for brevity.
def xpath(*a)
[1, 2]
end
You cannot let a method return multiple values. In order to do what you want, you have to change has_selector?, maybe something like this:
alias old_has_selector? :has_selector?
def has_selector? arg
case arg
when Array then old_has_selector?(*arg)
else old_has_selector?(arg)
end
end
Ruby has limited support for returning multiple values from a function. In particular a returned Array will get "destructured" when assigning to multiple variables:
def foo
[1, 2]
end
a, b = foo
a #=> 1
b #=> 2
However in your case you need the splat (*) to make it clear you're not just passing the array as the first argument.
If you want a cleaner syntax, why not just write your own wrapper:
def has_xpath?(xp)
has_selector?(*xpath(:css, xp))
end

For a Common Lisp library made of multiple packages, is there a standard way to export the API?

Obviously, the externally visible API is published by exporting symbols. But... what if I have multiple packages (say A, B and C) and A's exported symbols are not all meant to be part of the external API - some of them are needed for B and C? (similarly, B exports some symbols for A and C and some for the external API; C is the 'toplevel' package and all its exported symbols are part of the public API; I want to keep things modular and allow A to hide its innards from B and C, so I avoid '::').
My solution right now is to re-export everything that is meant to be public from C and document that the public API consists only of C's exported symbols and people should stay away from public symbols of A and B under pain of bugs and code broken in the future when internal interfaces change.
Is there a better way?
UPDATE: This is my implementation of my understanding of Xach's answer:
First, let me complete my example. I want to export symbols symbol-a-1 and symbol-a-2 from package a, symbols symbol-b-1 and symbol-b-2 from package b and symbols api-symbol-1 and api-symbol-2 from package c. Only the symbols exported from c are part of the public API.
First, the definition for a:
(defpackage #:a
(:use #:cl))
Note that there aren't any exported symbols :-)
A helper macro (uses Alexandria):
(defmacro privately-export (package-name &body symbols)
`(eval-when (:compile-toplevel :load-toplevel :execute)
(defun ,(alexandria:format-symbol *package*
"IMPORT-FROM-~a"
(symbol-name package-name)) ()
(list :import-from
,package-name
,#(mapcar (lambda (to-intern)
`',(intern (symbol-name to-intern) package-name))
symbols)))))
Use the macro to 'export privately' :-) :
(privately-export :a :symbol-a-1 :symbol-a-2)
Now the definition of b:
(defpackage #:b
(:use #:cl)
#.(import-from-a))
... b's 'exports':
(privately-export :b :symbol-b-1 :symbol-b-2)
... c's definition:
(defpackage #:c
(:use #:cl)
#.(import-from-a)
#.(import-from-b)
(:export :api-symbol-1 :api-symbol-2)
Problems with this approach:
a cannot use symbols from b (without importing symbols from b from a after both have been defined);
the syntax package:symbol is basically not usable for symbols exported 'privately' (it's either just symbol or package::symbol).
If A and B are primarily for the implementation of C, you can have C's defpackage form drive things with selective use of :import-from, since you can import things that aren't external. Then you can selectively re-export from there.
You could add a third package, D, that exports all public API symbols, and consider the A, B and C packages private. You could then qualify all definitions of functions and variables in the API package using qualified names like in
(defun D:blah () ...)
to make it easy to visually spot the definitions of public entry points.
Probably, the easiest way is proposed by Hans.
You may also wan to take a look at Tim Bradshaw's Conduit packages

Function objects in Smalltalk (or executing blocks with no `value:`)

Is it possible to send an anonymous message to an object? I want to compose three objects like this (think FP):
" find inner product "
reduce + (applyToAll * (transpose #(1 2 3) #(4 5 6)))
where reduce, applyToAll and transpose are objects and +, * and the two arrays are arguments passed to anonymous messages sent to those objects. Is it possible to achieve the same using blocks? (but no explicit usage of value:).
Perhaps what you really want to do is define a DSL inside Smalltalk?
With HELVETIA we explore a lightweight approach to embed new languages into the host language. The approach reuses the existing toolchain of editor, parser, compiler and debugger by leveraging the abstract syntax tree (AST) of the host environment. Different languages cleanly blend into each other and into existing code.
aRealObject reduceMethod: +;
applyToAll: *;
transpose: #(#(1 2 3) #(4 5 6));
evaluate
would work when aRealObject has defined the right methods. Where do you need a block?
You are looking for doesNotUnderstand:. If reduce is an object that does not implement + but you send it anyway, then instead its doesNotUnderstand: method will be invoked. Normally it just raises an error. But you can override the default, and access the selector + and the other argument and do whatever you like with them.
For simplicity, create a class Reduce. On its class side, define the method:
doesNotUnderstand: aMessage
^aMessage argument reduce: aMessage selector
Then you can use it like this:
Reduce + (#(1 2 3) * #(4 5 6))
which in a Squeak workspace answers 32, as expected.
It works because * is already implemented for Collections with suitable semantics.
Alternatively, add a class ApplyToAll with this class-side method:
doesNotUnderstand: aMessage
^aMessage argument collect: [:e | e reduce: aMessage selector]
and also add this method to SequenceableCollection:
transposed
^self first withIndexCollect: [:c :i | self collect: [:r | r at: i]]
Then you can write
Reduce + (ApplyToAll * #((1 2 3) #(4 5 6)) transposed)
which is pretty close to your original idea.

Resources