How to shadow a record in F# Program.fs? - f#

I'm following the F# book Get Programming with F# and got to the part about shadowing. The simplest example they provide doesn't seem to be possible, so I'm wondering if either this syntax was removed or changed for F# 6 shadowing? I haven't been able to find anything stating that or how to do what the book offers as shadowing a record.
type Address =
{ Street: string
Town: string
City: string }
let home = { Street = "123 Main Street"; Town = "The Town"; City = "The City" }
let home = { home with City = "Second City" }
let home = { home with City = "Third City" }
When trying to build get an error stating: Duplicate definition of value 'home'
Edit
So after searching for answers without success as to why this doesn't work I tried putting the above into a function like so:
let testFunction =
let home = { Street = "123 Main Street"; Town = "The Town"; City = "The City" }
let home = { home with City = "Second City" }
let home = { home with City = "Third City" }
0
and it worked just fine. So my question now is why does shadowing work within a function but not outside? Is there a conflict with scoping on a module level that doesn't happen within a function's scope?

To add some more detail to the existing answers, there are four different cases.
Local definitions. If you are inside a function body, you can use shadowing and this is quite useful when doing a computation in multiple steps:
let adjust index =
let index = max 0 index
let index = min 100 index
index
Local definitions inside class. You are similarly allowed to shadow local definitions inside a class:
type A() =
let foo = 1
let foo = 2
member x.Foo = foo
Top-level in a script file. If you are at the top level in a script file (something.fsx) then you are allowed shadowing. The idea with script files is that they would be run manually, so it is useful to have multiple different versions - you just run the one you want by hand:
let test = calculation1 ()
let test = caluclation2 ()
Top-level in a module (source file). The only case where shadowing does not work is when you are in a module (or .fs file which becomes a module implicitly). In a module, definitions are public and they are compiled as static members of a class, so there is also a technical limitation (you cannot have multiple class members of the same name).
module Constants =
let answer = 1
let answer = 42 // error FS0037: Duplicate definition of value

Why shadowing is limited to function body?
There are probably some technical reasons. But the core reasons are IMO:
Naming is hard. Shadowing eases the pain but it can be confusing.
Also F# supports "tick naming" (home') to have a similar but different name. It's a kind of safer shadowing.

Related

Associate string with function Lua

I have table like a:
{ "video", video_search ( message ) }.
How can i make check if input string = "video" then execute video_search command?
The correct answer to your question would be
if input_string == "video" then
video_search()
end
but going by the title and a fair bit of intuition, I assume you really want to ask
how do I associate functions with strings and, given a string, call the associated function?
To which the answer is a different one: first, restructure your table so it looks like this
local whatever = {
["video"] = video_search;
["audio"] = audio_search;
-- whatever else you have...
}
then you can just call the function like this:
local input = "video"
local message = "whatever a message is in your program"
whatever[input](message)

How can I map properties conditionally with MapStruct 1.2?

Is it possible with MapStruct 1.2 to map a source property with a specific value to a specific different value in the target?
I think about something like this:
public abstract class JiraKpmMapper {
#Mappings({
#Mapping(source = "mySource.propA", target = "myTarget.propX")
})
#ValueMappings({
#ValueMapping(source = "ABC", target = "XYZ"),
#ValueMapping(source = "123", target = "789")
})
public abstract MyTarget source2Target(final MySource mySource);
}
So that when MapStruct sees during the mapping that when mySource.propA has the value "ABC" myTarget.propX needs to be set to value "XYZ" and so forth.
To be more precisely, I even want something more elaborated:
The target should be a class haven three properties in which the resulting target value must be split into.
For instance, if mySource.propA has the value "ABC" the target myTarget should get a value like "V01.123.456.AB". This value in turn shall be split up in a preValue, a middleValue and an endValue:
preValue = "V01"
middleValue = "123.456"
endValue = "AB"
whereby there's no property holding the complete result string.
That's why I already wrote a custom mapper and I tell the MyMapper to use it via
#Mapper(componentModel = "spring", uses = MyCustomMapper.class)
This works so far but I can't achieve it to tell the MyCustomMapper to put "V01.123.456.AB" into the target when the souzrce comes with "ABC".
You can't really do that with MapStruct. The #ValueMapping annotation is for mapping of Enum(s).
In order to achieve what you are looking for you would need to do that in #BeforeMapping or #AfterMapping.
For example you can do something like:
#Mapper
public interface JiraKpmMapper {
#BeforeMapping
default void beforeMapping(#MappingTarget MyTarget target, MySource source) {
if (source.getPropY().equals("ABC") {
target.setPropX("V01.123.456.AB");
}
}
#Mapping(target = "propX", ignore = true) // This is now mapped in beforeMapping
MyTarget source2Target(final MySource mySource);
}
Your custom mapper then should have an #AfterMapping. Where you would convert the propX into your class. You can even do this as part of the #BeforeMapping I wrote and directly create your class (or invoke the method that does the conversion from String into a class)
you can do something like this
#Mapping(target = "myTarget.propX",expression="java(mySource.getPropA().equals(\"Abc\")?"\"V01.123.456.AB\":\"\")")

Replace string with other string in Lua

Good evening,
I am currently editing a Scoarboard in Lua and there are loaded by a GroupManager of the groups without formatting. These must now be formatted.
Example:
Current Rank: "superadmin"
Goal: "Super Admin"
func = function(ply) return ply:GetUserGroup() end
This funktion returns the groupname "superadmin" but now i don't have no idea
Since it's not possible to map from lower case words to upper case without knowing where to break words, you can create a table with all the possible combinations that you want to convert. For example:
local convtable = {
superadmin = "Super Admin",
somethingelse = "Something Else",
}
func = function(ply)
local group = ply:GetUserGroup()
return convtable[group] or group
end
This will return the converted text or the original string if it's not present in the mapping.

lua: user input to reference table

I am having trouble with my tables, I am making a text adventure in lua
local locxy = {}
locxy[1] = {}
locxy[1][1] = {}
locxy[1][1]["locdesc"] = "dungeon cell"
locxy[1][1]["items"] = {"nothing"}
locxy[1][1]["monsters"] = {monster1}
The [1][1] refers to x,y coordinates and using a move command I can successfully move into different rooms and receive the description of said room.
Items and monsters are nested tables since multiple items can be held there (each with their own properties).
The problem I am having is getting the items/monsters part to work. I have a separate table such as:
local monsters = {}
monsters["rat"] = {}
monsters["rat"]["Name"] = "a rat"
monsters["rat"]["Health"] = 5
monsters["rat"]["Attack"] = 1
I am using a table like this to create outlines for various enemy types. The monster1 is a variable I can insert into the location table to call upon one of these outlines, however I don't know how to reference it.
print("You are in ", locxy[x][y]["locdesc"]) -- this works
print("You can see a ", locxy[x][y]["monsters]["Name"],".") - does not work
So I would like to know how I can get that to work, I may need a different approach which is fine since I am learning. But I would also specifically like to know how to / if it possible to use a variable within a table entry that points to data in a separate table.
Thanks for any help that can be offered!
This line
locxy[x][y]["monsters]["Name"]
says
look in the locxy table for the x field
then look in the y field of that value
look in the "monsters"` field of that value
then look in the "Name" field of that value
The problem is that the table you get back from locxy[x][y]["monsters"] doesn't have a "Name" field. It has some number of entries in numerical indices.
locxy[x][y]["monsters][1]["Name"] will get you the name of the first monster in that table but you will need to loop over the monsters table to get all of them.
Style notes:
Instead of:
tab = {}
tab[1] = {}
tab[1][1] = {}
you can just use:
tab = {
[1] = {
{}
}
}
and instead of:
monsters = {}
monsters["rat"] = {}
monsters["rat"]["Name"] = "foo"
you can just use:
monsters = {
rat = {
Name = "foo"
}
}
Or ["rat"] and ["Name"] if you want to be explicit in your keys.
Similarly instead of monsters["rat"]["Name"] you can use monsters.rat.Name.

F# Referencing Types

I am working on a project where the F# code will be consumed by other .NET projects - so I am using classes. I created a code file like this:
namespace StockApplication
open System
type Stock =
{Symbol: String;
DayOpen: Decimal;
Price: Decimal;
}
member x.GetChange () =
x.Price - x.DayOpen
member x.GetPercentChange() =
Math.Round(x.GetChange()/x.DayOpen,4)
This works fine when I consume it from some unit tests written in C#. For example:
[TestMethod]
public void CreateStock_ReturnsValidInstance()
{
Stock stock = new Stock("TEST", 10, 10.25M);
Assert.IsNotNull(stock);
}
I then went to create another file with another class. This class uses the 1st class so I made sure it was below the original class in VS2012. When I created the next class, I can see it available via intellisense.
namespace StockApplication
open System
type StockTicker() =
member x.GetStock () =
StockApplication.Stock
However, every attept to either new it or refer it gives me the same error:
Error 1 The value, constructor, namespace or type 'Stock' is not
defined
Does anyone have any insight on why I can just simply new up a class that I created in F# in another F# file?
Thanks in advance.
Your C# test having Stock stock = new Stock("TEST", 10, 10.25M); that was compiled without a problem prompts to believe that F# constructor for the Stock should look the same. But this is not true and, perhaps, was the source of your confusion.
Your original
type Stock =
{Symbol: String;
DayOpen: Decimal;
Price: Decimal; }
is of F# type Record indeed, not an ordinary class. The following excerpt from MSDN applies:
Record construction also differs from class construction. In a record type, you cannot define a constructor.
Meaning that
let stock = Stock("ABC"; 10M; 10M)
will produce error FS0039: The value or constructor 'Stock' is not defined while
let stock = { Symbol = "ABC"; DayOpen = 10M; Price = 10M; }
will successfully create a record instance.
In order to build an instance of type Stock in your second F# type StockTicker you should use record construction syntax, something like
member x.GetStock () = { Symbol = "MSFT"; DayOpen = 32M; Price = 32.5M; }
which compiles without any problems.
When it comes to interop use of F# record from C# the latter follows the syntax that you applied in your test method.
OK, after digging into this reference (MSDN was 0 help) here, I found the answer.
Here is the syntax for the Stock class:
namespace StockApplication
open System
type Stock = class
val Symbol: String
val DayOpen: Decimal
val Price: Decimal
new (symbol, dayOpen, price) =
{
Symbol = symbol;
DayOpen = dayOpen;
Price = price
}
member x.GetChange () =
x.Price - x.DayOpen
member x.GetPercentChange() =
Math.Round(x.GetChange()/x.DayOpen,4)
end
And here is the syntax for the consuming class:
namespace StockApplication
type StockTicker() =
member x.GetStock () =
let y = new Stock("AET",1m,1m)
y.DayOpen

Resources