Why do I have to cast typeof to string with switch to make it work ?
This doesn't work:
typeof: type? get 'optional
switch typeof [
word! [
print "word"
]
string! [
print "string"
]
]
This works:
typeof: type? get 'optional
switch to-string typeof [
"word" [
print "word"
]
"string" [
print "string"
]
]
switch type?/word :optional [
word! [ print "word" ]
string! [ print "string" ]
]
OR
switch type? :optional reduce [
word! [ print "word" ]
string! [ print "string" ]
]
The reason is that the REBOL doesn't reduce ("evaluate") the cases in the switch statement. Without the /word refinement, the type? function returns a datatype!, but the switch statement tries to match this against a word!, and it fails.
I realize this might be confusing, so your best bet is either to convert the type to a string (as you did), or use one of the two idioms I've suggested. I prefer the first one, using type?/word.
Related
pickerData = [[["A"], ["i","ii","iii"]],[["B"],["iv","v","vi","vii"]]]
}
Error: Contextual type 'String' cannot be used with array literal
Please advice how to use the array
Heterogenous literal collection types must be annoated:
Try this:
let pickerData: [[[String]]] =
[
[
["A"],
["i","ii","iii"]
],
[
["B"],
["iv","v","vi","vii"]
]
]
I applied the GREL expression "value.split(/a/)" to some cells:
abcdef -> [ "", "bcdef" ]
bcdefa -> [ "bcdef" ]
badef -> [ "b", "def" ]
I can't understand why the first cell gives me a "" element in the resulting table. Is it a bug?
Thanks!
I don't know Java enough to comment on the source code for this function, but according to one of the developers of Open Refine this behavior is normal (edit : More details in Owen's comment, below). This is why there are other functions to split a string.
value.smartSplit(/a/), for example, gives a more consistent result when sep is at the begining or at the end of the string:
row value value.smartSplit(/a/)
1. abcdef [ "", "bcdef" ]
2. bcdefa [ "bcdef", "" ]
3. badef [ "b", "def" ]
This is the same result as using partition() with the omitfragment = true option enabled:
row value value.partition(/a/, true)
1. abcdef [ "", "bcdef" ]
2. bcdefa [ "bcdef", "" ]
3. badef [ "b", "def" ]
A simple example:
If I type #"w" in style "area" how do I get an #"z"? (ex. "qwerty ww" -> "qzerty zz")
As you want the conversion on the fly, you can either modify R3-GUI before loading. So load r3-gui.r3 down to your local directory. Then you add the line if key == #"w" [key: #"z"] to the function do-text-key, so it looks like
do-text-key: funct [
"Process text face keyboard events."
face [object!]
event [event! object!]
key
] [
text-key-map/face: face
text-key-map/shift?: find event/flags 'shift
if no-edit: not tag-face? face 'edit [
key: any [select/skip text-key-map/no-edit key 2 key]
]
either char? key [
if key == #"w" [key: #"z"]
text-key-map/key: key
switch/default key bind text-key-map/chars 'event [
unless no-edit [
insert-text-face face key
]
]
] [
if find event/flags 'control [
key: any [select text-key-map/control key key]
]
text-key-map/key: key
switch/default key text-key-map/words [return event]
]
none
]
Probably the official way would be to use on-key wih Rebol3
load-gui
view [
a: area on-key [ ; arg: event
if arg/type = 'key [
if arg/key == #"w" [arg/key: #"z"]
]
do-actor/style face 'on-key arg face/style
]
]
And finally a way to do this with Rebol2 on the fly
key-event: func [face event] [
if event/type = 'key [
if all [event/key = #"w" ] [
append a/text #"z"
focus a
view w
return false
]
]
event
]
insert-event-func :key-event
view w: layout [
a: area
]
After reading some files of r3-gui (text-caret.r3, text-cursor.r3, text-edit.r3, text-keys.r3, text.r3) and the editor, I found a solution that allows me to insert not only a character but also string:
do %r3-gui.r3
insertText-moveCursor-updateFace: func [
face
string
n-move
][
insert-text-face face string
move-cursor face 'left n-move false
update-text-caret face
see-caret face
show-later face
]
i-m-u: :insertText-moveCursor-updateFace
view [
area on-key [
either arg/type = 'key [
switch/default arg/key [
#"w" [i-m-u face/names/text-box "z" 0]
#"[" [i-m-u face/names/text-box "[]" 1]
#"$" [i-m-u face/names/text-box "func [] []" 4]
] [
;switch/default
do-actor/style face 'on-key arg face/style
]
] [
;arg/type != 'key
do-actor/style face 'on-key arg face/style
]
]
]
Area is a compound styles. It is composed of a text-box and a scroller. They are contained in face/names.
it sure seems that there's no easy way to do this ... how can i ensure that certain fields in my multi match query going to actually be boosted correctly so that exact matches show up at the top?
i honestly seem to have tried this a multitude of ways, but maybe someone knows the answer ...
in my movie and music database, i'm trying to search multiple fields at once, but ensure that exact matches make it to the top and that certain fields such as title and artist name have more boost.
here's the main portion of my query...
"query": {
"bool": {
"should": [
{
"multi_match": {
"type": "phrase_prefix",
"query": "brave",
"max_expansions": 10,
"fields": [
"title^3",
"artists.name^2",
"starring.name^2",
"credits.name",
"tracks^0.1"
]
}
}
],
"minimum_number_should_match": 1
}
}
as you see, the query is 'brave'. it just so happens there's a movie called brave. perfect, i want it at the top - since not only is it an exact match, but the match is in the title. however, there's a popular song called 'brave' from sara bareilles which ends up on top. why?
i've tried every analyzer known to man, custom and otherwise, and i've tried changing the 'type' parameter to every other permutation (phrase, best_fields, cross_fields, most_fields), and it just doesn't seem to honor the fact that i'm effectively trying to either promote 'title' and 'artists.name' and 'starring.name' and DEMOTE 'tracks'.
is there any way i can ensure all exact matches show up at the top (especially in title, etc) followed by expansions, etc?
any suggestions would be helpful.
EDIT
the analyzer i'm currently using which seems to work better than others is a custom one i call 'nameAnalyzer' which is made up of a 'lowercase' filter and 'keyword' tokenizer only.
here's some example documents in the order in which they're appearing in the results:
fields": {
"title": [
"Brave"
],
"credits.name": [
"Kelly MacDonald",
"Emma Thompson",
"Billy Connolly",
"Julie Walters",
"Kevin McKidd",
"Craig Ferguson",
"Robbie Coltrane"
],
"starring.name": [
"Emma Thompson",
"Julie Walters",
"Billy Connolly",
"Kevin Mckidd",
"Kelly Macdonald"
]
,
fields": {
"credits.name": [
"Hilary Weeks",
"Scott Wiley",
"Sarah Sample",
"Debra Fotheringham",
"Dustin Christensen",
"Russ Dixon"
],
"title": [
"Say Love"
],
"artists.name": [
"Hilary Weeks"
],
"tracks": [
"Say Love",
"Another Second Chance",
"It's A Good Day",
"Brave",
"I Found Me",
"Hero",
"Tell Me",
"Where I Am",
"Better Promises",
"Even When"
]
,
fields": {
"title": [
"Brave Little Toaster"
],
"credits.name": [
"Randy Bennett",
"Jim Jackman",
"Randy Cook",
"Judy Toll",
"Jon Lovitz",
"Tim Stack",
"Timothy E. Day",
"Thurl Ravenscroft",
"Deanna Oliver",
"Phil Hartman",
"Jonathon Benair",
"Joe Ranft"
],
"starring.name": [
"Jon Lovitz",
"Thurl Ravenscroft",
"Tim Stack",
"Timothy E. Day",
"Deanna Oliver"
]
},
"fields": {
"title": [
"Braveheart"
],
"credits.name": [
"Bernard Horsfall",
"Martin Dempsey",
"James Robinson",
"Robert Paterson",
"Alan Tall",
"Rupert Vansittart",
"Donal Gibson",
"Malcolm Tierney",
"Sandy Nelson",
"Sean Lawlor"
],
"starring.name": [
"Brendan Gleeson",
"Sophie Marceau",
"Mel Gibson",
"Patrick Mcgoohan",
"Catherine Mccormack"
]
}
maybe someone knows why the second title ... (in this case not sara bareilles as i said before, but) Hillary Weeks - who has a track called 'brave' ... why is it before title 'braveheart' and 'brave little toaster'?
EDIT AGAIN
to further complicate the situation, what if i had a 'rank' field that was a part of my document? i'm finding it very difficult to add that to my _score field using a script score function...
"functions": [
{
"script_score": {
"script": "_score * 1/ doc['rank'].value"
}
}
]
I'm trying to create a dispatcher of functions in Rebol 3, so that for each string the program receives there's an associated function to be called.
For example:
handlers: make map! [
"foo" foo-func
"bar" bar-func
]
where foo-func and bar-func are functions:
foo-func: func [ a b ] [ print "foo" ]
bar-func: func [ a b ] [ print "bar" ]
The idea is to select the function starting from the string, so:
f: select handlers "foo"
so that executing f is the same as executing foo-func and then call f with some arguments:
f param1 param2
I tried quoting the words in the map!, or using get-words but without success.
Using a get-word! at the console, without passing through a map! it works:
>> a: func [] [ print "Hello world!" ]
>> a
Hello world!
>> b: :a
>> b
Hello world!
Any help appreciated.
select handlers "foo" only get the word foo-func:
f: select handlers "foo"
probe f ;will get: foo-func
You need to get its content:
f: get f
f 1 2 ;will print "foo"
Or more compact:
f: get select handlers "foo"
It's better to actually have the reference to the function in the map, rather than a word that refers to the function. If you store a word then you have to make sure the word is bound to an object which has a reference to that function, like this:
handlers: object [
foo-func: func [ a b ] [ print "foo" ]
bar-func: func [ a b ] [ print "bar" ]
]
handler-names: map [
"foo" foo-func
"bar" bar-func
]
apply get in handlers select handler-names name args
But if you just have a reference to the function in your map, you don't have to do the double indirect, and your code looks like this:
handlers: map reduce [
"foo" func [ a b ] [ print "foo" ]
"bar" func [ a b ] [ print "bar" ]
]
apply select handlers name args
Cleaner code, and more efficient too. Or if you're careful enough, like this:
handlers/(name) a b
The path method above will also work if you want the code to do nothing if there is no handler - common in cases where you have optional handlers, such as in GUIs.
You can even have more than one reference to the same function with different key names. You don't have to assign functions to words, they're just values. You can also use the path method to collect the handlers in the first place, saving a reduce.
handlers: make map! 10 ; preallocate as many entries as you expect
handlers/("foo"): func [ a b ] [ print "foo" ]
handlers/("bar"): func [ a b ] [ print "bar" ]
handlers/("baz"): select handlers "bar" ; multiple references
That path syntax is just another way to call poke, but some prefer it. We have to put the string values in parens because of a (hopefully temporary) syntax conflict, but within those parens the string keys work. It's a faster alternative to do select or poke.
foo-func in your map is just an unevaluated word
>> type? select handlers "foo"
== word!
You should first create your functions and then reduce the block, you use for creating your handler map so
handlers: make map! reduce [
"foo" :foo-func
"bar" :bar-func
]
then you have functions inside your map
>> type? select handlers "foo"
== function!
Try:
....
f: do select handlers "foo"
....