This code shows how to make a function mutate its input - one of the things we come to F# to avoid.
type Age = { mutable n : int }
let printInside a = printfn "Inside = %d" a.n
let inside a =
a.n <- a.n + 1
a.n
let a = {n = 1}
printInside a //a = 1
inside a
printInside a //a = 2
That being said, how do I do the same bad thing with [<Struct>] Records? I suspect that ref or byref may be involved but I just can't seem to get it to work.
type [<Struct>] Age = { mutable n : int }
let printInside a = printfn "Inside = %d" a.n
let inside a =
a.n <- a.n + 1
a.n
let a = {n = 1}
printInside a //a = 1
inside a
printInside a //a = 2
The fundamental issue is that a mutable field can only be modified if the struct itself is mutable. As you noted, we need to use byref in the declaration of Age. We also need to make sure a is mutable and lastly we need to use the & operator when calling the function inside. The & is the way to call a function with a byref parameter.
type [<Struct>] Age = { mutable n : int }
let printInside a = printfn "Inside = %d" a.n
let inside (a : Age byref) =
a.n <- a.n + 1
a.n
let mutable a = {n = 1}
printInside a //a = 1
inside &a
printInside a //a = 2
Now that I get the pattern, here is a simple example (just an int instead of a struct record) of how to mutate values passed into a function:
let mutable a = 1
let mutate (a : byref<_>) = a <- a + 1
mutate &a
a //a = 2
Related
I have a string that contains different ranges and I need to find their value
var str = "some text x = 1..14, y = 2..4 some text"
I used the substringBefore() and substringAfter() methodes to get the x and y but I can't find a way to get the values because the numbers could be one or two digits or even negative numbers.
One approach is to use a regex, e.g.:
val str = "some text x = 1..14, y = 2..4 some text"
val match = Regex("x = (-?\\d+[.][.]-?\\d+).* y = (-?\\d+[.][.]-?\\d+)")
.find(str)
if (match != null)
println("x=${match.groupValues[1]}, y=${match.groupValues[2]}")
// prints: x=1..14, y=2..4
\\d matches a single digit, so \\d+ matches one or more digits; -? matches an optional minus sign; [.] matches a dot; and (…) marks a group that you can then retrieve from the groupValues property. (groupValues[0] is the whole match, so the individual values start from index 1.)
You could easily add extra parens to pull out each number separately, instead of whole ranges.
(You may or may not find this as readable or maintainable as string-manipulation approaches…)
Is this solution fit for you?
val str = "some text x = 1..14, y = 2..4 some text"
val result = str.replace(",", "").split(" ")
var x = ""; var y = ""
for (i in 0..result.count()-1) {
if (result[i] == "x") {
x = result[i+2]
} else if (result[i] == "y") {
y = result[i+2]
}
}
println(x)
println(y)
Using KotlinSpirit library
val rangeParser = object : Grammar<IntRange>() {
private var first: Int = -1
private var last: Int = -1
override val result: IntRange
get() = first..last
override fun defineRule(): Rule<*> {
return int {
first = it
} + ".." + int {
last = it
}
}
}.toRule().compile()
val str = "some text x = 1..14, y = 2..4 some text"
val ranges = rangeParser.findAll(str)
https://github.com/tiksem/KotlinSpirit
Can anyone fix my buggy Lua object system?
Different instances have different numeric fields
But .. when I add tables to my initialization fields, then those tables are shared between different instances (see example, below).
What I think is that I need to do a deep copy on initial fields but I can't see where. My code is below. Any suggestions?
Object = {}
function Object:new (o)
-- o = deep_copy(o) or {} -- <== this didn't work
-- self = deep copy(self) -- <== this didn't work
o = o or {}
setmetatable(o, self)
self.__index = self
self.__tostring = show
return o
end
Account = Object:new{balance = 0,all={}}
function Account:push(v)
self.all[#self.all+1] = v
end
function Account:deposit(v)
self.balance = self.balance + v end
function Account:withdraw (v)
if v > self.balance then
error"insufficient funds" end
self.balance = self.balance - v
end
function show(i, str,sep)
str,sep = "{",""
for k,v in pairs(i) do
if type(v) ~= "function" then
str = str..sep..tostring(k)..":"..tostring(v)
sep = ", "
end
end
return str .. "}"
end
Just to illustrate the problem, below I have two instances a and b
When I update a,b's numeric fields, then different instances get different values.
But when I update the all table in one instance a, it changes it in the other instance b.
a=Account:new()
b=Account:new()
a:deposit(100)
b:deposit(200)
b:push(10)
b:push(20)
a:push(300)
print("a all", show(a), show(a.all))
print("b all", show(b), show(b.all))
The output should be:
a all {balance:100} {3:300}
b all {balance:200} {1:10, 2:20}
But what actually comes out is:
a all {balance:100} {1:10, 2:20, 3:300}
b all {balance:200} {1:10, 2:20, 3:300}
You do self.__index = self, and your prototype has an all field, but you never set one in the objects that you create. As a result, accesses to it (as push does) will always go through __index and end up hitting the prototype.
As Joseph said, you need to create distinct all for every object.
You could either write function Account:new() or write Object:new() function which accepts initializer (so that you would not need to implement distinct :new() for every class):
Object = {__init = function(o) end}
function Object:new(o, init)
-- when creating an instance:
-- o: the object itself
-- when creating a class:
-- o: table containing shared fields and methods
-- init: initializer for instances of this class
o = o or {}
self.__init(o)
setmetatable(o, self)
self.__index = self
if init then
function o.__init(o)
self.__init(o)
init(o)
end
end
return o
end
Account = Object:new({}, function(o) o.all={}; o.balance=0; end)
function Account:push(v)
self.all[#self.all+1] = v
end
function Account:deposit(v)
self.balance = self.balance + v
end
function Account:withdraw (v)
if v > self.balance then
error"insufficient funds" end
self.balance = self.balance - v
end
function show(i, str,sep)
str,sep = "{",""
for k,v in pairs(i) do
if type(v) ~= "function" then
str = str..sep..tostring(k)..":"..tostring(v)
sep = ", "
end
end
return str .. "}"
end
Object.__tostring = show
a=Account:new()
b=Account:new()
a:deposit(100)
b:deposit(200)
b:push(10)
b:push(20)
a:push(300)
print("a all", show(a), show(a.all))
print("b all", show(b), show(b.all))
If you'd like to inherit from Object, easiest is to create a new constructor for account as well. This should set a balance and and all for each object, not on the class itself.
Object = {}
Account = {}
function Object:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
self.__tostring = show
return o
end
function Account:new(o)
o = o or Object:new(o)
setmetatable(o, self)
self.__index = self
o.balance = 0
o.all = {}
return o
end
a all {all:table: 0x55ab93ec70d0, balance:100} {1:300}
b all {all:table: 0x55ab93ec6ed0, balance:200} {1:10, 2:20}
Was trying to check a 2d vector and noticed some weird behavior that I haven't been able to find a explanation for.
fn main() {
let mut main_loop = vec![];
let mut x = 0;
let board_x = 10;
let mut y = 0;
let board_y = 10;
while y < board_y {
let mut row = vec![];
while x < board_x {
let v = random::<bool>();
println!("x:{}", x);
row.push(v);
x = x + 1;
}
println!("y:{}", y);
main_loop.push(row);
y = y + 1;
}
}
This only prints
x:0
x:1
x:2
x:3
x:4
x:5
x:6
x:7
x:8
x:9
y:0
y:1
y:2
y:3
y:4
y:5
y:6
y:7
y:8
y:9
Shouldn't this be printing out x:1 - x:10 10 times? Also what was even stranger was that when I looped back over the vectors using a nested for loops for each row, it counted out 60 indexes before exiting out. What am I missing?
Shouldn't this be printing out x:1 - x:10 10 times?
Why would it? You never set x back to zero after the inner loop is done.
Besides which, this sort of iteration should be done with a for loop:
for x in 0..10 { ... }
[...] when I looped back over the vectors using a nested for loops for each row, it counted out 60 indexes before exiting out.
I don't know; you didn't post that code, and I can't see any reason it would do that.
If I use the following code in Swift repl, I get unexpected results:
1> func addA(s: String)->String {
2. return s + "a"
3. }
4.
5. func addB(s: String)->String {
6. return s + "b"
7. }
8>
9> println(addA(""))
a
10> println(addB(""))
b
11> println(addA(addB("")))
ba
12> let p = addA(addB(""))
p: ((String)) = {
_core = {
_baseAddress = 0x0000000100500060
_countAndFlags = 2
_owner = (instance_type = Builtin.RawPointer = 0x0000000100500040)
}
}
13> println(p)
ba
14> let q = "a" + "b"
q: String = "ab"
why does declaring p produce this behaviour, while declaring q does not?
All that's happening here is that the REPL is letting you look inside Swift at some of the underlying efficiencies. p is stored as some sort of function composition. When evaluation is needed, it is evaluated. If you didn't want to see the sausage being made, you should not have entered the sausage factory.
In Haskell you can say
main = do
let x = 5
print x
and this will not compile:
main = do
let x = 5
in print x
But if I am using explicit layout, this does not compile:
main = do {
let x = 5;
print x;
}
but this works:
main = do {
let x = 5
in print x;
}
Am I right? Is there anyplace I can read more about explicit layout and do and let notation? Section 3.14 of the Haskell 98 report seems to me to suggest that my third example should work, as it says I can write
do { let DECLS; stmts }
and it translates to
let DECLS in do { stmts }
The normative answer to your question can be found in the Haskell report's description of the layout rule.
Briefly, you need to place a semicolon between your let block and the next statement of the do block. That semicolon needs to lie outside of the let block. If you don't use layout for the let block, that's easy, just say:
let {x = 5};
However, if you do use layout for the let block, then the only way to close the let block is to start a line in a column before the column of x. So that means you'd have to write something like this:
main = do {
let x = 5
; print x;
}
Oh, and for your other example, again with layout a semicolon is getting inserted before the in, so your code desugars to:
main = do {
let {x = 5
};
in print x
}