Imagine we have some method
MyClass>>#method: arg
Transcript crShow: 'executed'
So when you do MyClass new method: 1 the transcript is filled with "executed" lines.
Now I want to skip this method if arg is 0. I've tried to install an instead metalink with a condition:
link := MetaLink new
condition: [ :arguments |
arguments first = 0 ]
arguments: #(arguments);
control: #instead.
(MyClass >> #method:) ast link: link
But then the method does not run anymore and I want to run it if the arg is not 0.
I've also tried to do the condition in the metaobject in this way:
link := MetaLink new
metaObject: [ :ast :arguments :receiver |
arguments first = 0
ifFalse: [
ast compiledMethod
valueWithReceiver: receiver
arguments: arguments ] ];
selector: #value:value:value:;
arguments: #(node arguments receiver);
control: #instead.
(MyClass >> #method:) ast link: link
But in this case you end up in a infinite recursion, as the metalink is called over and over again although I thought that ast compiledMethod should return a compiled method and not the reflective counterpart
yes, it looks like "instead hooks" are always executed "instead" of the original method, even if the link condition does not hold, the difference is just whether we return the value of the instead link evaluation or just nil.
Maybe this should be changed for instead links.
As solution for your usecase, you can use a before link that just returns the receiver if the condition holds:
| ml |
ml := MetaLink new.
ml control: #before.
ml condition:[:args | args first = 0] arguments:#(arguments).
ml selector:#value:.
ml metaObject:[:context | context return].
ml arguments:{#context}.
(MyObject>>#method:) ast link:ml.
the #context is the key for the thisContext refication (RFThisContextReification)
Related
I am working through Miguel Morales Deep Reinforcement Learning book and I have come across some syntax that I am unfamilar with. I have looked at the tutorials for dictionary comprehension and lambda functions and I am yet to find what the square brackets does at the end of the lamda call. Can anyone help?
def policy_improvement(value, mdp, gamma=1.0):
''' Performs improvement of a given policy by evaluating the actions for each state and choosing greedily. '''
Q = np.zeros((len(mdp), len(mdp[0])), dtype=np.float64)
for state in range(len(mdp)):
for action in range(len(mdp[state])):
for transition_prob, state_prime, reward, done in mdp[state][action]:
Q[state][action] += transition_prob * (reward + gamma * value[state_prime] * (not done)) # Update the Q value for each action.
new_policy_pie = lambda state: {state:action for state, action in enumerate(np.argmax(Q, axis=1))}[state]
return new_policy_pie
The lambda is made of two parts:
# 1. Create a map of state to action
d = {state:action for state, action in enumerate(np.argmax(Q, axis=1))}
# 2. Return the value for argument `state`
d[state]
So the [state] bit is part of the lambda, it's the dictionary selector.
The intent might have been to write a fail-safe lambda in case the state does not exist, but then they should use .get(state) instead of [].
So in the end, your code above could be replaced with:
lambda state: np.argmax(Q, axis=1)[state]
What does this do, and is there a simpler way to write it?
Collection>>into: a2block
| all pair |
all := ([:allIn :each| allIn key key: allIn value. each])
-> (pair := nil -> a2block).
pair key: all.
self inject: all
into: [:allIn :each| allIn value: (allIn key value: allIn value value: each). allIn].
^all value
If you want to find out, the best way is to try it, possibly step by step thru debugger.
For example, try:
(1 to: 4) into: #+.
(1 to: 4) into: #*.
You'll see a form of reduction.
So it's like inject:into: but without injecting anything.
The a2block will consume first two elements, then result of this and 3rd element, etc...
So we must understand the selector name as inject:into: without inject:: like the implementation, it's already a crooked way to name things.
This is implemented in Squeak as reduce:, except that reduce: would be well too obvious as a selector, and except that it would raise an Error if sent to an empty collection, contrarily to this which will answer the strange recursive artifact.
The all artifact contains a block to be executed for reduction as key, and current value of reduction as value. At first step, it arranges to replace the block to be executed with a2block, and the first value by first element. But the recursive structure used to achieve the replacement is... un-necessarily complex.
A bit less obfuscated way to write the same thing would be:
into: a2block
| block |
self ifEmpty: [self error: 'receiver of into: shall not be empty'].
block := [:newBlock :each| block := newBlock. each].
^self inject: a2block into: [:accum :each| block value: accum value: each]
That's more or less the same principle: at first iteration, the block is replaced by the reduction block (a2block), and first element is accumulated.
The reduction only begins at 2nd iteration.
The alternative is to check for first iteration inside the loop... One way to do it:
into: a2block
| first |
self ifEmpty: [self error: 'receiver of into: shall not be empty'].
first := Object new.
^self inject: first into: [:accum :each |
accum == first
ifTrue: [each]
ifFalse: [a2block value: accum value: each]].
There are many other ways to write it, more explicitely using a boolean to test for first iteration...
let list p = if List.contains " " p || List.contains null p then false else true
I have such a function to check if the list is well formatted or not. The list shouldn't have an empty string and nulls. I don't get what I am missing since Check.Verbose list returns falsifiable output.
How should I approach the problem?
I think you don't quite understand FsCheck yet. When you do Check.Verbose someFunction, FsCheck generates a bunch of random input for your function, and fails if the function ever returns false. The idea is that the function you pass to Check.Verbose should be a property that will always be true no matter what the input is. For example, if you reverse a list twice then it should return the original list no matter what the original list was. This property is usually expressed as follows:
let revTwiceIsSameList (lst : int list) =
List.rev (List.rev lst) = lst
Check.Verbose revTwiceIsSameList // This will pass
Your function, on the other hand, is a good, useful function that checks whether a list is well-formed in your data model... but it's not a property in the sense that FsCheck uses the term (that is, a function that should always return true no matter what the input is). To make an FsCheck-style property, you want to write a function that looks generally like:
let verifyMyFunc (input : string list) =
if (input is well-formed) then // TODO: Figure out how to check that
myFunc input = true
else
myFunc input = false
Check.Verbose verifyMyFunc
(Note that I've named your function myFunc instead of list, because as a general rule, you should never name a function list. The name list is a data type (e.g., string list or int list), and if you name a function list, you'll just confuse yourself later on when the same name has two different meanings.)
Now, the problem here is: how do you write the "input is well-formed" part of my verifyMyFunc example? You can't just use your function to check it, because that would be testing your function against itself, which is not a useful test. (The test would essentially become "myFunc input = myFunc input", which would always return true even if your function had a bug in it — unless your function returned random input, of course). So you'd have to write another function to check if the input is well-formed, and here the problem is that the function you've written is the best, most correct way to check for well-formed input. If you wrote another function to check, it would boil down to not (List.contains "" || List.contains null) in the end, and again, you'd be essentially checking your function against itself.
In this specific case, I don't think FsCheck is the right tool for the job, because your function is so simple. Is this a homework assignment, where your instructor is requiring you to use FsCheck? Or are you trying to learn FsCheck on your own, and using this exercise to teach yourself FsCheck? If it's the former, then I'd suggest pointing your instructor to this question and see what he says about my answer. If it's the latter, then I'd suggest finding some slightly more complicated function to use to learn FsCheck. A useful function here would be one where you can find some property that should always be true, like in the List.rev example (reversing a list twice should restore the original list, so that's a useful property to test with). Or if you're having trouble finding an always-true property, at least find a function that you can implement in at least two different ways, so that you can use FsCheck to check that both implementations return the same result for any given input.
Adding to #rmunn's excellent answer:
if you wanted to test myFunc (yes I also renamed your list function) you could do it by creating some fixed cases that you already know the answer to, like:
let myFunc p = if List.contains " " p || List.contains null p then false else true
let tests =
testList "myFunc" [
testCase "empty list" <| fun()-> "empty" |> Expect.isTrue (myFunc [ ])
testCase "nonempty list" <| fun()-> "hi" |> Expect.isTrue (myFunc [ "hi" ])
testCase "null case" <| fun()-> "null" |> Expect.isFalse (myFunc [ null ])
testCase "empty string" <| fun()-> "\"\"" |> Expect.isFalse (myFunc [ "" ])
]
Tests.runTests config tests
Here I am using a testing library called Expecto.
If you run this you would see one of the tests fails:
Failed! myFunc/empty string:
"". Actual value was true but had expected it to be false.
because your original function has a bug; it checks for space " " instead of empty string "".
After you fix it all tests pass:
4 tests run in 00:00:00.0105346 for myFunc – 4 passed, 0 ignored, 0
failed, 0 errored. Success!
At this point you checked only 4 simple and obvious cases with zero or one element each. Many times functions fail when fed more complex data. The problem is how many more test cases can you add? The possibilities are literally infinite!
FsCheck
This is where FsCheck can help you. With FsCheck you can check for properties (or rules) that should always be true. It takes a little bit of creativity to think of good ones to test for and granted, sometimes it is not easy.
In your case we can test for concatenation. The rule would be like this:
If two lists are concatenated the result of MyFunc applied to the concatenation should be true if both lists are well formed and false if any of them is malformed.
You can express that as a function this way:
let myFuncConcatenation l1 l2 = myFunc (l1 # l2) = (myFunc l1 && myFunc l2)
l1 # l2 is the concatenation of both lists.
Now if you call FsCheck:
FsCheck.Verbose myFuncConcatenation
It tries a 100 different combinations trying to make it fail but in the end it gives you the Ok:
0:
["X"]
["^"; ""]
1:
["C"; ""; "M"]
[]
2:
[""; ""; ""]
[""; null; ""; ""]
3:
...
Ok, passed 100 tests.
This does not necessarily mean your function is correct, there still could be a failing combination that FsCheck did not try or it could be wrong in a different way. But it is a pretty good indication that it is correct in terms of the concatenation property.
Testing for the concatenation property with FsCheck actually allowed us to call myFunc 300 times with different values and prove that it did not crash or returned an unexpected value.
FsCheck does not replace case by case testing, it complements it:
Notice that if you had run FsCheck.Verbose myFuncConcatenation over the original function, which had a bug, it would still pass. The reason is the bug was independent of the concatenation property. This means that you should always have the case by case testing where you check the most important cases and you can complement that with FsCheck to test other situations.
Here are other properties you can check, these test the two false conditions independently:
let myFuncHasNulls l = if List.contains null l then myFunc l = false else true
let myFuncHasEmpty l = if List.contains "" l then myFunc l = false else true
Check.Quick myFuncHasNulls
Check.Quick myFuncHasEmpty
// Ok, passed 100 tests.
// Ok, passed 100 tests.
I am trying to learn Erlang and I am working on the practice problems Erlang has on the site. One of them is:
Write the function time:swedish_date() which returns a string containing the date in swedish YYMMDD format:
time:swedish_date()
"080901"
My function:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
string:substr((integer_to_list(YYYY, 3,4)++pad_string(integer_to_list(MM))++pad_string(integer_to_list(DD)).
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
I'm getting the following errors when compiled.
demo.erl:6: syntax error before: '.'
demo.erl:2: function swedish_date/0 undefined
demo.erl:9: Warning: function pad_string/1 is unused
error
How do I fix this?
After fixing your compilation errors, you're still facing runtime errors. Since you're trying to learn Erlang, it's instructive to look at your approach and see if it can be improved, and fix those runtime errors along the way.
First let's look at swedish_date/0:
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
Why convert the list to a tuple? Since you use the list elements individually and never use the list as a whole, the conversion serves no purpose. You can instead just pattern-match the returned tuple:
{YYYY,MM,DD} = date(),
Next, you're calling string:substr/1, which doesn't exist:
string:substr((integer_to_list(YYYY,3,4) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD))).
The string:substr/2,3 functions both take a starting position, and the 3-arity version also takes a length. You don't need either, and can avoid string:substr entirely and instead just return the assembled string:
integer_to_list(YYYY,3,4) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
Whoops, this is still not right: there is no such function integer_to_list/3, so just replace that first call with integer_to_list/1:
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
Next, let's look at pad_string/1:
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
There's a runtime error here because '0' is an atom and you're attempting to append String, which is a list, to it. The error looks like this:
** exception error: bad argument
in operator ++/2
called as '0' ++ "8"
Instead of just fixing that directly, let's consider what pad_string/1 does: it adds a leading 0 character if the string is a single digit. Instead of using if to check for this condition — if isn't used that often in Erlang code — use pattern matching:
pad_string([D]) ->
[$0,D];
pad_string(S) ->
S.
The first clause matches a single-element list, and returns a new list with the element D preceded with $0, which is the character constant for the character 0. The second clause matches all other arguments and just returns whatever is passed in.
Here's the full version with all changes:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
{YYYY,MM,DD} = date(),
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
pad_string([D]) ->
[$0,D];
pad_string(S) ->
S.
But a simpler approach would be to use the io_lib:format/2 function to just format the desired string directly:
swedish_date() ->
io_lib:format("~w~2..0w~2..0w", tuple_to_list(date())).
First, note that we're back to calling tuple_to_list(date()). This is because the second argument for io_lib:format/2 must be a list. Its first argument is a format string, which in our case says to expect three arguments, formatting each as an Erlang term, and formatting the 2nd and 3rd arguments with a width of 2 and 0-padded.
But there's still one more step to address, because if we run the io_lib:format/2 version we get:
1> demo:swedish_date().
["2015",["0",56],"29"]
Whoa, what's that? It's simply a deep list, where each element of the list is itself a list. To get the format we want, we can flatten that list:
swedish_date() ->
lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).
Executing this version gives us what we want:
2> demo:swedish_date().
"20150829"
Find the final full version of the code below.
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).
UPDATE: #Pascal comments that the year should be printed as 2 digits rather than 4. We can achieve this by passing the date list through a list comprehension:
swedish_date() ->
DateVals = [D rem 100 || D <- tuple_to_list(date())],
lists:flatten(io_lib:format("~w~2..0w~2..0w", DateVals)).
This applies the rem remainder operator to each of the list elements returned by tuple_to_list(date()). The operation is needless for month and day but I think it's cleaner than extracting the year and processing it individually. The result:
3> demo:swedish_date().
"150829"
There are a few issues here:
You are missing a parenthesis at the end of line 6.
You are trying to call integer_to_list/3 when Erlang only defines integer_to_list/1,2.
This will work:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
string:substr(
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD))
).
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
In addition to the parenthesis error on line 6, you also have an error on line 10 where yo use the form '0' instead of "0", so you define an atom rather than a string.
I understand you are doing this for educational purpose, but I encourage you to dig into erlang libraries, it is something you will have to do. For a common problem like this, it already exists function that help you:
swedish_date() ->
{YYYY,MM,DD} = date(), % not useful to transform into list
lists:flatten(io_lib:format("~2.10.0B~2.10.0B~2.10.0B",[YYYY rem 100,MM,DD])).
% ~X.Y.ZB means: uses format integer in base Y, print X characters, uses Z for padding
I am doing a model in Alloy to represent a subset of Java language. Below we have some elements of this model:
sig Method {
id : one MethodId,
param: lone Type,
return: one Type,
acc: lone Accessibility,
b: one Block
}
abstract sig Expression {}
abstract sig StatementExpression extends Expression {}
sig MethodInvocation extends StatementExpression{
pExp: lone PrimaryExpression,
id_methodInvoked: one Method,
param: lone Type
}
sig Block {
statements: set StatementExpression
}
pred noRecursiveMethodInvocationCall [] {
all bl:Block | all mi, mi2: MethodInvocation | all m:Method |
bl in m.b && mi in bl.statements
&& mi2 = mi.*(id_methodInvoked.b.statements) =>
m != mi2.id_methodInvoked
}
The problem is that the predicate noRecursiveMethodInvocationCall apparently is not working since the instances generated contains methods being invoked in a recursive way (even indirectly, e.g. m1 invokes m2, that invokes m3 that in turn invokes m1) and i want to avoid recursion.
The instances are generated through another model, see below:
open javametamodel_withfield_final
one sig BRight, CRight, BLeft, CLeft, Test extends Class{
}
one sig F extends Field{}
fact{
BRight in CRight.extend
BLeft in CLeft.extend
F in BRight.fields
F in CLeft.fields
all c:{Class-BRight-CLeft} | F !in c.fields
}
pred law6RightToLeft[]{
proviso[]
}
pred proviso [] {
some BRight.extend
some BLeft.extend
#(extend.BRight) > 2
#(extend.BLeft) > 2
no cfi:FieldAccess | ( cfi.pExp.id_cf in extend.BRight || cfi.pExp.id_cf in BRight || cfi.pExp.id_cf in extend.BLeft || cfi.pExp.id_cf in BLeft) && cfi.id_fieldInvoked=F
some Method
}
run law6RightToLeft for 9 but 15 Id, 15 Type, 15 Class
Please, does anyone have any clue what the problem is?
Thanks in advance for the attention,
Follow-on query
Still regarding this question, the predicate suggested solves the recursion problem:
pred noRecursiveMethodInvocationCall [] {
no m:Method
| m in m.^(b.statements.id_methodInvoked)
}
However, it causes inconsistency with another predicate (see below), and instances are not generated when both predicates exist.
pred atLeastOneMethodInvocNonVoidMethods [] {
all m:Method
| some mi:MethodInvocation
| mi in (m.b).statements
}
Any idea why instances can not be generated with both predicates?
You might look closely at the condition
mi2 = mi.*(id_methodInvoked.b.statements)
which seems to check whether the set of all statements reachable recursively from mi is equal to the single statement mi2. Now, unless I've confused myself about multiplicities again, mi2 is a scalar, so in any case where the method in question has a block with more than one method-invocation statement, this condition won't fire and the predicate will be vacuously true.
Changing = to in may be the simplest fix, but in that case I expect you won't get any non-empty instances, because you're using * and getting reflexive transitive closure, and not ^ (positive transitive closure).
It looks at first glance as if the condition might be simplified to something like
pred noRecursion {
no m : Method
| m in m.^(b.statements.idMethodInvoked)
}
but perhaps I'm missing something.
Postscript: a later addition to the question asks why no instances are generated when the prohibition on recursion is combined with a requirement that every method contain at least one method invocation:
pred atLeastOneMethodInvocNonVoidMethods [] {
all m:Method
| some mi:MethodInvocation
| mi in (m.b).statements
}
Perhaps the simplest way to see what's wrong is to imagine constructing a call graph. The nodes of the graph are methods, and the arcs of the graph are method invocations. There is an arc from node M1 to node M2 if the body of method M1 contains an invocation of method M2.
If we interpret the two predicates in terms of the graph, the predicate noRecursiveMethodInvocationCall means that the graph is acyclic. The predicate atLeastOneMethodInvocNonVoidMethods means that every node in the graph has at least one outgoing arc.
Try it with a single method M. This method must contain a method invocation, and this method invocation must invoke M (since there is no other method in the universe). So we have an arc from M to M, and the graph has a cycle. But the graph is not allowed to have a cycle. So we cannot create a one-method universe that satisfies both predicates.
Try again with two methods, M1 and M2. Let M1 call M2. Now, what does M2 call? It can't call M1 without making a cycle. It can't call M2 without making a cycle. Again we fail.
I don't have the time just now to look it up, but I think you'll find there is a basic theorem of graph theory that if the number of edges equals the number of nodes, the graph must have a cycle.