F# List of Union Types - list

I want a list of Reports. Report can be either Detail or Section types.
module Data
type Section = { Header: string;
Lines: string list;
Total: string }
type Detail = { State: string;
Divisions: string list;
Sections: Section list }
type Summary = { State: string;
Office: string;
Sections: Section list }
type Report = Detail | Summary
Then in my code, I'd like to do the following:
let mutable (reports:Report list) = []
...
reports <- detail::reports
// or
reports <- summary::reports
The compiler complains in the first case: "The expression was expected to have type Report but here has type Detail", and appropriately similarly in the second case.
Am I out of my mind for wanting to do such a thing? Should I be thinking about the problem differently? Because Report is either Detail or Summary, shouldn't a list of Report accept either a Detail or a Summary? What is a Report list if not a list of Detail or Summary?
Thanks.

You've just got your syntax a bit wrong:
type Report = Detail of Detail | Summary of Summary
reports <- (Detail detail)::reports
// or
reports <- (Summary summary)::reports
In your code you've basically just defined the Report type to be an enum with the two possible values Details or Summary (these are like labels, not the types of different subtypes in this context). Discriminated unions in F# are explicitly tagged, so you've also got to use one of the union constructors to create an instance to put into the list.

You need to change your Report type to:
type Report = Detail of Detail | Summary of Summary
since your current definition just names the two cases of your Report type, and these names are not related to the existing Detail and Summary types.
You can then filter the Detail and Summary elements using List.choose e.g.
let details = reports |> List.choose (function Detail(d) -> Some(d) | _ -> None)

Related

Terraform Splat Expression Giving "Invalid template interpolation value"

I am using data sources in Terraform to fetch a list of ids of my security groups as such:
data "aws_security_groups" "test" {
filter {
name = "group-name"
values = ["the-name"]
}
}
output "security_group_id" {
value = "The id is ${data.aws_security_groups.test.ids[*]}"
}
However, this is giving me the following error:
Error: Invalid template interpolation value
on main.tf line 11, in output "security_group_id":
11: value = "The id is ${data.aws_security_groups.test.ids[*]}"
|----------------
| data.aws_security_groups.test.ids is list of string with 1 element
Cannot include the given value in a string template: string required.
But if I use data.aws_security_groups.test.ids[0] instead it displays the ID.
Can someone help me to display the list of IDs?
First, I want to note that you don't necessarily need to combine this list with a string message at all if you don't want to, because Terraform will accept output values of any type:
output "security_group_ids" {
value = data.aws_security_groups.test.ids
}
If having them included as part of a bigger string is important for your underlying problem then you'll need to make a decision about how you want to present these multiple ids in your single string. There are various different ways you could do that, depending on what you intend to do with this information.
One relatively-straightforward answer would be to make the string include a JSON representation of the list using jsonencode, like this:
output "security_group_id_message" {
value = "The ids are ${jsonencode(data.aws_security_groups.test.ids)}"
}
If you want a more human-friendly presentation then you might prefer to use a multi-line string instead, in which case you can customize the output using string templates.
output "security_group_id_message" {
value = <<-EOT
The ids are:
%{ for id in data.aws_security_groups.test.ids ~}
- ${id}
%{ endfor ~}
EOT
}
Or, for an answer somewhere in between, you could use join to just concatenate the values together with a simple delimiter, like this:
output "security_group_id_message" {
value = "The ids are ${join(",", data.aws_security_groups.test.ids)}"
}
Note that I removed the [*] from your reference in all of these examples, since it isn't really doing anything here: data.aws_security_groups.test.ids is already an iterable collection, and so is compatible with all of the language features I used in the examples above.
IIRC the provider considers this ids attribute to be a set of strings rather than a list of strings, and so that [*] suffix could potentially be useful in other situations to force converting the set into a list if you need it to be typed that way, although if that is your intent then I'd suggest using one of the following instead so that it's clearer to a future reader what it does:
sort(data.aws_security_groups.test.ids) (if it being in lexical order is important to the behavior; Terraform uses lexical sorting by default anyway, but calling sort is a good prompt to a reader unfamiliar with Terraform to look up that function to see what the actual sort order is.)
tolist(data.aws_security_groups.test.ids) (functionally equivalent to sort above when it's a set of strings, but avoids the implication that the specific ordering is important, if all that matters is that it's a list regardless of the ordering)

Type mismatch with operation on lists

New in Ocaml and I'm trying to implement a couple of functions to manage a list of a custom types.
I'm trying to manage a list of types, and when I need to add a new element to the list I need to make some checks.
This is my actual code:
open Ast
open Easy_logging
exception DuplicateEntry
let logger = Logging.make_logger "SymbolTable" Debug [Cli Debug]
type variable = {
id: string;
tipe: Ast.typ
}
type dec = {
variables: variable list;
parent: dec option
}
let begin_block table =
if List.length table > 1 then
let last_scope = List.nth table ((List.length table) -1) in
let new_scope = {variables=[]; parent=last_scope} in
new_scope::table
else {variables=[]; parent=None}::table
let add_entry symbol info table =
let tail_scope = List.nth table ((List.length table) - 1) in
{id=symbol; tipe=info}::tail_scope.variables;
logger#debug "Added inside the table the node with id %s" symbol
let rec lookup symbol table = failwith "lookup: Not implemented yet"
I'm trying to implement the operation begin_block but I'm getting the following error:
File "src/symbol_table.ml", line 31, characters 16-21:
31 | new_scope::table
^^^^^
Error: This expression has type dec option list
but an expression was expected of type dec list
Type dec option is not compatible with type dec
Command exited with code 2.
Compilation unsuccessful after building 26 targets (0 cached) in 00:00:01.
In this case, the table is the list
I'm losing somethings but at the moment I'm not able to find the error :/, maybe this is a stupid question.
You're omitting a lot of context here, and I had to remove references to missing modules in order to reproduce, which means I've made several assumptions that may be wrong.
Given that, my guess is that you've copied code that originally used the Base or Core standard library replacement, where the List.nth function returns an 'a option, as opposed to the standard OCaml implementation which will raise an exception instead if the given index is out of bounds.
The reason I think so is that the parent field of dec has type dec option and is assigned last_scope directly, which means last_scope must have the same type. And if List.nth has type 'a list -> int -> 'a, then 'a must have type dec option, which means table must have type dec option list. And you can't prepend a dec to a dec option list, hence the error.
Lastly, a good way to find the cause of issues like this is to make your assumptions explicit by annotating the type of variables. For example, annotating the type of table here will give you a different error, narrowing it down last_scope having the type dec but being expected to have type dec option when being assigned to parent.

Printing multiple lines of a dictionary

Suppose I define type
type person = { last_name: string; first_name: string; age: int};;
let person1 = {last_name="Doe"; first_name="John"; age=30};;
How can I print
Last name : Doe
First name : John
Age : 30
I thought using
match person1 with
| {last_name=ln; first_name=fn; age=a} -> print_string ...;;
but it seems not the way to go. If person1 and person were defined to be a dictionary with 1000 elements, then that solution doesn't hold.
Is there a better way to challenge that problem? Be aware that I have to use the functional paradigm. So I can't use while or for loop directly
It's hard to answer your question because you seem to have two different ideas of your type simultaneously. You can't have a type that's both a record and a dictionary. It's not possible.
Generally speaking, a dictionary is a collection of things. The convention for collections in OCaml is that they have a function named iter that traverses the collection.
Imagine you have an abstract collection defined by a module C. Conventionally you'll have a type 'a C.t for each collection, where 'a is the type of the elements of the collection. You'll also have (conventionally) a function C.iter of this type:
C.iter : ('a -> unit) -> 'a C.t -> unit
This means you can pass a function (like your printing function) to C.iter, and then also pass a collection. The iter function will traverse the collection and call your function for every element.
In your case the module C would define the dictionary you're imagining, and the type person C.t would be the type of a dictionary of the records you show above. The function C.iter would have the type (person -> unit) -> person C.t -> unit. In other words, it would take a function and apply it to all the persons in the dictionary, one after the other.
We can't really say more unless we know the details of the dictionary that you are planning to create.

How to sequence a query in F#?

So I have a query like this one
let query =
query {
for person in people do
select person
}
And I'd like to have it sequenced.
let sequence : seq<Person> = query
But I can't find any information on how to do it, maybe I've become bad at using search engines.
I'm getting unexpected type compiling expections using things like |> seq.ofList and ToList().
The expression was expected to have the type seq<Person> but here has the type Generic.List<Person>.
The result of a query expression has type IQueryable<_>, which is a subtype of IEnumerable<_> (for which seq<_> is a synonym), so you can simply change the type:
let mySeq : seq<_> = myQuery
Or, if you want to avoid a type annotation, use the built-in seq function, which does the same thing:
let mySeq = seq myQuery

Erlang: Sorting or Ordering Function for List of Tuple Lists

I have trouble sorting two related but separate lists of tuple lists. One list is made up of tuple lists representing a blog post. The other list is made up of tuple lists representing a comment post.
The problem is when you would like the same order based on blog id value. The lists for blog posts is sorted via the date value. So you cannot just sort numerically via blog id for both blog and comment post. And you cannot just sort the comment post via date value because the date values of blog and related comment post may be different.
I am not sure how to approach the problem - at least not in an elegant way.
Should I use lists:nth and consequently get each tuple list and position value? Then I would get the value of blog id, Then I would search in the list for comment posts for that id. Get the value of that tuple list. Associate the value of that tuple list in a new list with the appropriate nth position value.
Should I use the lists:sort function?
Any suggestions with code samples much appreciated.
Here are two sample lists of tuple lists that can be used as a basis :
[[{<<"blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2010-12-4T6:10:12">>},
{<<"message">>,<<"la di da bo di do">>}],
[{<<"blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2009-12-3T10:09:33">>},
{<<"message">>,<<"that is cool">>}],
[{<<"blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-2T18:12:29">>},
{<<"message">>,<<"i like san francisco">>}]]
[[{<<"comment_id">>,<<"n6">>},
{<<"related_blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2010-12-5T15:10:12">>},
{<<"message">>,<<"yup really neat">>}],
[{<<"comment_id">>,<<"y2">>},
{<<"related_blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-6T10:09:33">>},
{<<"message">>,<<"yes but rent is expensive">>}],
[{<<"comment_id">>,<<"x4">>},
{<<"related_blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2009-12-5T16:12:29">>},
{<<"message">>,<<"sounds like a hit">>}]]
And the desired output is the following with first list unchanged and second list reordered :
[[{<<"blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2010-12-4T6:10:12">>},
{<<"message">>,<<"la di da bo di do">>}],
[{<<"blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2009-12-3T10:09:33">>},
{<<"message">>,<<"that is cool">>}],
[{<<"blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-2T18:12:29">>},
{<<"message">>,<<"i like san francisco">>}]]
[ [{<<"comment_id">>,<<"x4">>},
{<<"related_blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2009-12-5T16:12:29">>},
{<<"message">>,<<"sounds like a hit">>}],
[{<<"comment_id">>,<<"n6">>},
{<<"related_blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2010-12-5T15:10:12">>},
{<<"message">>,<<"yup really neat">>}],
[{<<"comment_id">>,<<"y2">>},
{<<"related_blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-6T10:09:33">>},
{<<"message">>,<<"yes but rent is expensive">>}]]
Ok, new try then :)
We have:
-module(foo).
-compile(export_all).
Basic module exports to test the thing
blogs() ->
[[{<<"blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2010-12-4T6:10:12">>},
{<<"message">>,<<"la di da bo di do">>}],
[{<<"blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2009-12-3T10:09:33">>},
{<<"message">>,<<"that is cool">>}],
[{<<"blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-2T18:12:29">>},
{<<"message">>,<<"i like san francisco">>}]].
Your definition of blogs.
comments() ->
[[{<<"comment_id">>,<<"n6">>},
{<<"related_blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2010-12-5T15:10:12">>},
{<<"message">>,<<"yup really neat">>}],
[{<<"comment_id">>,<<"y2">>},
{<<"related_blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-6T10:09:33">>},
{<<"message">>,<<"yes but rent is expensive">>}],
[{<<"comment_id">>,<<"x4">>},
{<<"related_blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2009-12-5T16:12:29">>},
{<<"message">>,<<"sounds like a hit">>}]].
Your definition of comments.
sorted_comments() ->
[[{<<"comment_id">>,<<"x4">>},
{<<"related_blog_id">>,<<"a2">>},
{<<"postDate">>,<<"2009-12-5T16:12:29">>},
{<<"message">>,<<"sounds like a hit">>}],
[{<<"comment_id">>,<<"n6">>},
{<<"related_blog_id">>,<<"b8">>},
{<<"postDate">>,<<"2010-12-5T15:10:12">>},
{<<"message">>,<<"yup really neat">>}],
[{<<"comment_id">>,<<"y2">>},
{<<"related_blog_id">>,<<"a9">>},
{<<"postDate">>,<<"2009-12-6T10:09:33">>},
{<<"message">>,<<"yes but rent is expensive">>}]].
Your definition of being sorted.
sort(Blogs, Comments) ->
%% Create list of blog id's
Bs = [proplists:get_value(<<"blog_id">>, B) || B <- Blogs],
Fetch all the blog_id values from the Blogs.
%% Create the numbering
DB = dict:from_list([Item || Item <- lists:zip(Bs,
lists:seq(1, length(Bs)))]),
Number the order the blogs occur in. Stuff these into a dict for fast lookup later.
%% Sorter function:
F = fun(I, J) ->
II = proplists:get_value(<<"related_blog_id">>,
I),
JJ = proplists:get_value(<<"related_blog_id">>,
J),
dict:fetch(II, DB) =< dict:fetch(JJ, DB)
end,
This function compares two Comments, I, J to each other based on their related blog_id.
{Blogs, lists:sort(F, Comments)}.
Return what we want to return.
sort_test() ->
{blogs(), sorted_comments()} == sort(blogs(), comments()).
Tester function.
2> c(foo).
{ok,foo}
3> foo:sort_test().
true