Monte Carlo 3x Speedup

Hey all, I've been experimenting with Mojo for some simple RL and wrote a blog post about it. Thought it might be interesting to share here! https://open.substack.com/pub/alexinch/p/reinforcing-learning-using-mojo-to
Reinforcing Learning: Using Mojo🔥 to learn 3x faster
Rewriting a Monte Carlo RL approach in Mojo for a 3x speed increase, with some drawbacks...
12 Replies
Darin Simmons
Darin Simmons3mo ago
Thank you for taking the time. Good stuff. @Aloysius Aloysius, I checked the bug reports and did not see one for round(). Would you like to create one or if you prefer I would be willing?
Aloysius
Aloysius3mo ago
Hi, I'm out and about right now - if you have the time please feel free to create a report, otherwise I can do this evening!
Darin Simmons
Darin Simmons3mo ago
I'll do it (Turns out I stepped in it, lol, still working on it) With this commit they added the ability to round FloatLiterals so it works in nightly but it's still waiting on all the conformances to work so that all the declared Int and Floats work correctly
sora
sora3mo ago
Could you elaborate a bit on what exactly “you don’t get” regarding var
Aloysius
Aloysius3mo ago
Yeah sure, it made sense to me when there were let and var declarations. Now that everything uses var, why not just add it implicitly? Seems closer to Python and I don't see the downside
mad alex 1997
mad alex 19973mo ago
I think
var x:Int = 5
var x:Int = 5
looks better than
x:Int = 5
x:Int = 5
and it lets you set variable types without initializing
var x:Int
var x:Int
sora
sora3mo ago
There are many reasons i can think of - Mojo has different scoping rules than Python, declaration is indeed different from assignment. - You can shadow names in small scopes like loop body, if branches, etc. - A variable in Mojo has to be defined and initialised on every path even if it's never used. - We don't want Python's ugly global and nonlocal So it's really, for many usecases (like scripting), we can rely on the compiler to add them for us (we have that in defs), but for system programming purposes, the markers are necessary. Python's semantics is tailed to the fact that it's a dynamically typed scripting language. Consider the following Python program:
if expr:
a = 10
use(a)
if expr:
a = 10
use(a)
where expr is a vey complex expression that can be prove to be always true, but not constant folded into true. It's a valid program in Python, because we won't run into problems at runtime, we can simply say that a is defined in the function scope, and call it a day. In Mojo, however, it's very difficult to argue that a is defined only in the true branch in a program like
if expr:
a = 10
use(a)
if expr:
a = 10
use(a)
but not the above. We need the var keyword to indicate the scope explicitly:
var a: Int
if expr:
a = 10 # a defined in the outer scope
use(a)
var a: Int
if expr:
a = 10 # a defined in the outer scope
use(a)
VS
if expr:
var a = 10
use(a)
# a not defined here
if expr:
var a = 10
use(a)
# a not defined here
In summary, Python can't warn you of this problem, and the programer can get this right most of the time, so the rules are very relaxed. But in a compiled language, the compiler have to get this correct every single time, so it needs more information and more precise scoping (you see this in pyright as well) If you still find difficult to see the neccecity of some kind of marker, look no further than python's own dataclass declaration: Python works just fine with good old classes and naked attribute assignment like self.a = a in __init__. But if you want type checking, you will have to list everything in the class definition itself beforehand.
Darin Simmons
Darin Simmons3mo ago
I guess sora likes var 😉
sora
sora3mo ago
I’m actually pretty against the removal of let.
Aloysius
Aloysius3mo ago
Thanks for the extensive reply! I can see the benefits of var for clarity. I do still kind of think implicitly handling is ok: like if your example was:
a: Int
if expr:
a = 10
use(a)
a: Int
if expr:
a = 10
use(a)
But I can see how that's less clear. My comment was an observation from early use, no doubt I'll get used to it.
sora
sora3mo ago
In fact that in defs, it is inferred to match python behaviour.
def f():
a: Int # this is rather redundant, given (*)
if expr:
a = 10 # (*) `a` already has function scope
use(a)
def f():
a: Int # this is rather redundant, given (*)
if expr:
a = 10 # (*) `a` already has function scope
use(a)
Now there is no way to define something like, for there is no way to distinguish explicit typing and variable declaration
fn f():
var a: Int
if expr:
a = 10
else:
var a = 100
use(a)
use(a)
fn f():
var a: Int
if expr:
a = 10
else:
var a = 100
use(a)
use(a)
To make my position very clear: I agree with you that if we can find a good set of implicit rules, it will look way nicer. In fact, Guido himself joined this server and proposed the same thing (a: T instead of var a: T) to Chris. It's just that being a system programming language closes many doors.
benny
benny3mo ago
I agree with this, i like enforced immutability at runtime
Want results from more Discord servers?
Add your server