I am currently writing a code in SML that takes in a string list full of numbers and spaces. The code must combine the numbers up to the space, then create a new list item for the next set of numbers, and so on.
For example, the list ["1", "", "2", "3", "", "4", "5", "6"] would return the list ["1", "23", "456"].
My current non-error attempt includes the code below.
fun conc(L) =
case L of
[] => ""
| x::xs => x ^ conc(xs);
fun intParse(L as x::xs) =
let
val intStr = conc(L)
in
intStr :: intParse(xs)
end;
I wanted to write something like the code below, but couldn't without error. This is not exact code, more-so pseudocode that I couldn't figure out.
fun strToInt(nil) = []
| strToInt(L) =
let
fun conc(y::ys) =
if hd(ys) <> "" then y ^ conc(ys)
else y ^ ""
in
conc(L) :: strToInt(xs)
end;
As you are iterating recursively over a list, you need a base case. You've figured that out. It's [].
The other thing you need is an accumulator or accumulators you can pass along as you iterate. These accumulators can be "hidden" using a locally scoped helper function to which you provide the accumulators in their initial states.
val lst = ["1", "", "2", "3", "", "4", "5", "6"];
fun lstTransform(lst) =
let
fun aux([], str, acc) =
if str = "" then List.rev(acc)
else List.rev(str :: acc)
| aux(x::xs, str, acc) =
if x = "" andalso str <> "" then
aux(xs, "", str :: acc)
else if x = "" then
aux(xs, "", acc)
else
aux(xs, str ^ x, acc)
in
aux(lst, "", [])
end;
When you hit the base case, you want to check if the accumulator for the "current" string you've built (str) is empty or not. If it's empty, we just return the accumulator. If not, we need to add that string onto the accumulator.
In either case, because of the way lists are built, they'd be backwards, so we reverse them.
Otherwise you're evaluating the first element in the list and deciding based on that how to update your state for the next iteration.
This type of iteration over a list and accumulation of a new value is exactly what List.foldl is made for. This function lets us get rid of a lot of the boilerplate. We provide a function which works on each element in the list and the accumulator; and the initial state of the accumlator; and the list to work on.
let
val (str, acc) =
List.foldl
(fn (x, (str, acc)) =>
if x = "" andalso str <> "" then ("", str :: acc)
else if x = "" then ("", acc)
else (str ^ x, acc))
("", [])
lst
in
if str = "" then List.rev(acc)
else List.rev(str :: acc)
end;
Here is my attempt...
fun squoosh lst =
let
fun collect_and_accumulate acc collected =
fn [] => List.rev (if collected = "" then acc else collected :: acc)
| (""::ys) => collect_and_accumulate (if collected = "" then acc else collected :: acc) "" ys
| (x::ys) => collect_and_accumulate acc (collected ^ x) ys;
in
collect_and_accumulate [] "" lst
end;
Run Code Snippet below to see the result
runCode();
<pre id="code" class="lang-ml s-code-block">
fun squoosh lst =
let
fun collect_and_accumulate acc collected =
fn [] => List.rev (if collected = "" then acc else collected :: acc)
| (""::ys) => collect_and_accumulate (if collected = "" then acc else collected :: acc) "" ys
| (x::ys) => collect_and_accumulate acc (collected ^ x) ys;
in
collect_and_accumulate [] "" lst
end;
squoosh ["1", "", "2", "3", "", "4", "5", "6"];
</pre>
<script src="https://unpkg.com/#sosml/interpreter#^1.5.0/build/interpreter.min.js"></script>
<script>
function runCode() {
try {
let initialState = Interpreter.getFirstState();
const code = document.getElementById('code');
let interpretationResult = Interpreter.interpret(code.innerText, initialState);
console.log(interpretationResult.state.toString({ stopId: initialState.id + 1 }));
} catch (error) {
console.error(error.name, "\n", error.message);
}
}
</script>
Related
I have a type defined as follows:
type Employee = {
Id: Guid
Name: string
Phone: string
Email: Option<string>
}
and an instance of this type:
let emp = {
Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
Name = "A"
Phone = "B"
Email = Some "E"
}
I want to extract the field names and values from this record type using reflection like the following:
let getFieldValueMappingOfARecordType (data: 'T) : seq<string * obj> =
let fieldValueMapping =
data.GetType()
|> FSharpType.GetRecordFields
|> Seq.map (
fun propertyInfo ->
(propertyInfo.Name, data |> propertyInfo.GetValue)
)
fieldValueMapping
Then invoking the above function with the instance of employee type
let mapping = getFieldValueMappingOfARecordType emp
|> Seq.toList
gives us:
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", Some "E")]
So far it's working well with non-optional type. But in case of optional types, it's returning the value of the field as either Some value or None. What I would like to do is to get the value when the field has Some value or make it null when it's None.
Essentially like the follwing:
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", "E")]
Or if the employee instance is like the following:
let emp = {
Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
Name = "A"
Phone = "B"
Email = None
}
Then,
val mapping : (string * obj) list =
[("Id", bc07e94c-b376-45a2-928b-508b888802c9); ("Name", "A"); ("Phone", "B");
("Email", null)]
This is what I have so far (non-working code):
open System
open Microsoft.FSharp.Reflection
open System.Reflection
type Employee = {
Id: Guid
Name: string
Phone: string
Email: Option<string>
}
let emp = {
Id = Guid "bc07e94c-b376-45a2-928b-508b888802c9"
Name = "A"
Phone = "B"
Email = Some "E"
}
let getSomeOrNull (t: Type) (o: obj) =
let opt = typedefof<option<_>>.MakeGenericType [| t |]
match (o :?> opt) with
| Some s ->
s
| None ->
null
let getValues (data: 'T) =
let values =
data.GetType()
|> FSharpType.GetRecordFields
|> Array.map (
fun propertyInfo ->
let value =
data |> propertyInfo.GetValue
let isOption =
propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() = typedefof<Option<_>>
match isOption with
| true ->
(propertyInfo.Name, (getSomeOrNull propertyInfo.PropertyType value))
| false ->
(propertyInfo.Name, value)
)
values
getValues emp
|> printfn "%A"
I think the only way to do this is with reflection:
let getSomeOrNull (t: Type) (o: obj) =
if isNull o then null
else t.GetProperty("Value").GetValue(o)
I think this should do the trick:
let getSomeOrNull (o: obj) =
match o with
| :? Option<string> as o -> a |> Option.toObj > box
| _ -> null
Hi my task is to recursively create an expression tree from a List input.
ex. ("+", 2, 3)
"+"
/ \
2 3
I know my recursion is off, but I can't figure out how to make it work. I've been at it for longer than I'm proud to admit. Any insight is appreciated! This is what I have so
fun TreeBuild(input:List<Any>): Pair<Tree, List<Any>>{
var tree = Tree(input.get(0), Unit, Unit)
var list = input
System.out.println(list)
if(input.size == 1 ){
list = list.drop(1)
return Pair(Tree(input.get(0), Unit, Unit), list)
}
var flag: Boolean = (input.get(0) is Int)
if (!flag){
list = list.drop(1)
tree.left = TreeBuild(list).first
list = list.drop(1)
tree.right = TreeBuild(list).first
}
return Pair(tree, list)
}
So it looks like the filter function on a Swift (2.x) dictionary returns a tuple array. My question is there an elegant solution to turning it back into a dictionary? Thanks in advance.
let dictionary: [String: String] = [
"key1": "value1",
"key2": "value2",
"key3": "value3"
]
let newTupleArray: [(String, String)] = dictionary.filter { (tuple: (key: String, value: String)) -> Bool in
return tuple.key != "key2"
}
let newDictionary: [String: String] = Dictionary(dictionaryLiteral: newTupleArray) // Error: cannot convert value of type '[(String, String)]' to expected argument type '[(_, _)]'
If you are looking for a more functional approach:
let result = dictionary.filter {
$0.0 != "key2"
}
.reduce([String: String]()) { (var aggregate, elem) in
aggregate[elem.0] = elem.1
return aggregate
}
reduce here is used to construct a new dictionary from the filtered tuples.
Edit: since var parameters has been deprecated in Swift 2.2, you need to create a local mutable copy of aggregate:
let result = dictionary.filter {
$0.0 != "key2"
}
.reduce([String: String]()) { aggregate, elem in
var newAggregate = aggregate
newAggregate[elem.0] = elem.1
return newAggregate
}
You can extend Dictionary so that it takes a sequence of tuples as initial values:
extension Dictionary {
public init<S: SequenceType where S.Generator.Element == (Key, Value)>(_ seq: S) {
self.init()
for (k, v) in seq { self[k] = v }
}
}
and then do
let newDictionary = Dictionary(newTupleArray)
I am trying to use purescript-lens to update a property of a nested record. However, when I compose lenses to get to the property, I get the following type error:
Warning: Error at src/Main.purs line 150, column 38 - line 152, column 3:
Error in declaration performAction
Cannot unify { description :: u24500 | u24501 } with Main.Item. Use --force to continue.
I'm relatively new to lenses and purescript, so it's probably something simple and obvious.
The relevant code that produces this error follows (yes, it's based on purescript-thermite-todomvc):
data Action
= NewItem String String String String String
| RemoveItem Index
| SetEditText String
| DoNothing
data Item = Item
{ description :: String
, keywords :: String
, link_title :: String
, profile :: String
, title :: String
}
data State = State
{ item :: Item
, editText :: String
}
_State :: LensP State { item :: _, editText :: _ }
_State f (State st) = State <$> f st
item :: forall r. LensP { item :: _ | r } _
item f st = f st.item <#> \i -> st { item = i }
editText :: forall r. LensP { editText :: _ | r } _
editText f st = f st.editText <#> \i -> st { editText = i }
itemDescription :: forall r. LensP { description :: _ | r } _
itemDescription f it = f it.description <#> \d -> it { description = d }
performAction :: T.PerformAction _ Action (T.Action _ State)
performAction _ action = T.modifyState (updateState action)
where
updateState :: Action -> State -> State
updateState (NewItem s1 _ _ _ _) = _State .. item .. itemDescription .~ s1
updateState (SetEditText s) = _State .. editText .~ s
updateState DoNothing = id
The property I'm trying to update is st.item.description and the above error refers to the line that starts "updateState (NewItem..." Curiously, the same error is also reported for the next line.
Any ideas on how to resolve the type error?
Thanks
I've "fixed" this by making the types of the lenses less general. I've also based the lenses on the syntax that Phil uses in his "24 days" review of purescript-lens. I find that syntax less opaque.
item :: LensP State Item
item = lens (\(State st) -> st.item) (\(State st) item -> State (st { item = item }))
editText :: LensP State String
editText = lens (\(State st) -> st.editText) (\(State st) editText -> State (st { editText = editText }))
itemDescription :: LensP Item String
itemDescription = lens (\(Item it) -> it.description) (\(Item it) description -> Item (it { description = description }))
Again, to keep the lens types simple, I've stripped out the use of the _State lens in performAction:
performAction :: T.PerformAction _ Action (T.Action _ State)
performAction _ action = T.modifyState (updateState action)
where
updateState :: Action -> State -> State
updateState (NewItem s1 _ _ _ _) = \st -> st # item..itemDescription.~ s1
updateState (SetEditText s) = \st -> st # editText.~ s
updateState DoNothing = id
I'm sure there's a more elegant, general, and complete solution, but that will have to wait until I understand purescript-lens better.
I'm trying to have a good access to multi-dimensional arrays with string indexes in Lua, here's basically what I'm trying to do:
rules =
{
{"S_RIGHT", "A_STOP", "S_RESULT"},
}
matrix = {}
for _,v in pairs(rules) do
if( matrix[ v[1] ] == nil ) then
matrix[ v[1] ] = {}
end
matrix[ v[1] ][ v[2] ] = v[3]
end
-- results in error ( attempt to index field 'S_NO' a nil value)
var = matrix["S_NO"]["S_RESULT"]
assert(var == nil, "Var should be nil")
A way to do it but quite verbose is:
var = matrix["S_NO"]
if var ~= nil then
var = var["S_RESULT"]
end
assert(var == nil, "Var should be nil")
Is there a way to make the first case to work ? ( less verbose )
Ok,
Found the answer.
If matrix is going to be read-only a correct approach would be:
local empty = {}
setmetatable(matrix, {__index=function() return empty end})
If I would like to allow writes and it's specifically two levels of tables, I could do:
setmetatable(matrix, {__index=function(t,k) local new={} rawset(t,k,new) return new end}
Hope this helps!