eradicator wrote: Wed Jun 12, 2019 7:01 am
Qon wrote: Tue Jun 11, 2019 7:23 pm
Any professional programmer will understand the simple functional style. Without a formal introduction, it is probably not known to many amateurs. But code understandability and maintainability are judged by professionals.
Do you not percieve yourself as extremely patronizing and arrogant? To me it looks mostly like you wanted to brag about your own "professionalism". Especially since you're saying it on a forum full of amateur and hobby-coders. (And i say "coders" here on purpose). Your tendency to ignore basic english spelling strengthens that impression to me. Written communication is difficult i know. And i'm half expexting a "it's your fault for not being a native speaker"-type answer. But maybe it's worth some time to think about it.
No. And not my intention. Factorio has many hobby coders but also many professionals in various fields, including programming. It's not really an achievement to brag about. It's not even a very specific accomplishment, it's just a statement of vocation. We all (adults) have our fields of expertise, programming is just a relevant field. You wouldn't say that I'm bragging if I state that I'm an adult, even if there are kids on this forum, right?
And I wasn't sure what was hard to understand about the code so I had to assume that it was in part the more esoteric concepts and not just the linebreaks.
I'm just spelling things with "Qon" for my own amusement. Nothing to take notice of.
I'm not a native English speaker either, so nuance might get lost when a message is translated twice and also in text.
eradicator wrote: Wed Jun 12, 2019 7:01 am And given the fact that my "200+ lines estimate" was meant as an eyeball estimate for intermediate hobby programmers this is hardly "off by an order of magnitude".
Yes, in hindsight I realise that your estimate was for hobby programmers. And the line count doubles when a few more needed line breaks are added.
eradicator wrote: Wed Jun 12, 2019 7:01 am
What is "bluebird"? Google finds exactly one hit, which seems to be a JS library. And it seems to be what you really meant was the general concept of a "promise"?
Bluebird was a comment for myself mostly. It's just a lambda calculus combinator, a language which uses lambda ("anonymous") functions only.
It's the compositional combinator (
function composition), written as "." in Haskell. It composes two functions into a new combined function. So not an asynchronous function call wrapper "promise". Though you can compose with those too.
You mentioned your python style preference. I like to use functional programming where it fits. And in languages with proper lambda function syntax it is standard to not split lines between each parameter in you function definition.
Code: Select all
local B = function(f) return function(g) return function(a) return f(g(a)) end end end
Is styled like these:
JS:
Haskell:
Code: Select all
B f g a = f (g a)
B = ( . ) -- or just use the built in function
Even though it doesn't make as much sense in Lua as in those languages because of it's awkward syntax. But as I said, I didn't choose Lua and I prefer to make it clear that the functions are going to be curried.
eradicator wrote: Wed Jun 12, 2019 7:01 am
Why...are you using string.find instead of type()?
I didn't feel like checking how Lua stores table arrays. And I thought I had read that Lua table keys were strings (always) like in JS. Because if so the keys would always be strings. But apparently you can do :
Code: Select all
local a = {}
a[1] = 'x'
a['1'] = 'y'
game.print(serpent.block(a))
But you can't do
with that table. Now I know. So yeah type() would work fine.
eradicator wrote: Wed Jun 12, 2019 7:01 am
And some problems:
typeFromName looks like it's being called onto the item table before ".name" is guaranteed to exist. I.e. the "bluebird" function creation has the wrong order of arguments (i fixed this by changing the constructor to take arguments in execution order instead of reverse order).
Oops.
eradicator wrote: Wed Jun 12, 2019 7:01 am
Code: Select all
function promise(f2,f1)
return function(arg)
return f2( f1(arg) )
end
end
No. You didn't.

And in function composition, the "reverse" order is the correct order. Mathematicians often read from right to left q:
I switched it in
eradicator wrote: Wed Jun 12, 2019 7:01 am
Code: Select all
function reformat (item) --no good name for this
local new = {}
for k,v in pairs(item_defaults) do
Why rename it if you don't have a good name for it? Reformat is equally good/bad name though I guess. And item_defaults doesn't exist because you removed the second parameter.
I fixed some other bugs you introduced (mostly missed variable renaming) and fixed some bugs I crafted myself earlier. And then styled it to a compromise between the bit excessively compact style (no more for-if combos as single lines) and your style. I don't like python blocks...
Would be 61 non-empty lines if non_difficulty_data was a one-liner.
Code: Select all
function compose(f, g) return function(arg)
return f(g(arg))
end end
function map(array, f)
local new = {}
for i, v in ipairs(array) do
table.insert(new, f(v, i, array))
end
return new
end
function reformat(new_format) return function(item)
local new = {}
for k,v in pairs(new_format) do
if type(k) == 'number' then new[v] = item[v] or item[k]
elseif (not new[k]) then new[k] = v end
end
for k, v in pairs(item) do
if type(k) ~= 'number' then new[k] = v end
end
return new
end end
function add_type(item)
item.type = data.raw.fluid[item.name] and 'fluid' or 'item'
return item
end
local non_difficulty_data = {
name = true,
type = true,
order = true,
localised_name = true,
localised_description = true,
crafting_machine_tint = true,
category = true,
subgroup = true,
}
function difficulty_data(difficulty)
if (difficulty == nil) then return end
local new = {}
local normalize_and_type = compose(add_type, reformat{'name', 'amount', amount = 1})
new.results = map(
difficulty.results or {{difficulty.result, difficulty.result_count}},
normalize_and_type
)
new.ingredients = map(
difficulty.ingredients,
normalize_and_type
)
return new
end
local deepcopy = util.table.deepcopy
function normalize_recipe(old_recipe)
local new = {}
old_recipe = deepcopy(old_recipe)
new.normal = difficulty_data(old_recipe.normal )
new.expensive = difficulty_data(old_recipe.expensive) or deepcopy(new.normal)
for k,v in pairs(old_recipe) do
if non_difficulty_data[k] then new[k] = v end
end
if not (new.normal or new.expensive) then
new.expensive = difficulty_data(old_recipe)
end
new.normal = new.normal or deepcopy(new.expensive)
new.icons = not (old_recipe.icon or old_recipe.icons) and nil or map(
old_recipe.icons or {{old_recipe.icon, old_recipe.icon_size}},
reformat{'icon', 'icon_size', icon_size = 32}
)
if old_recipe.normal == false then new.normal .enabled = false end
if old_recipe.expensive == false then new.expensive.enabled = false end
return new
end