language-ext: query expression with group by and Validation does not work
Hello Louthy and All, I have a query expression that works for data as an Option but when I try to do the same query as a Validation it does not work.
Here is the case that works as an option:
public static Func<IEnumerable<Option<CellData>>, IEnumerable<Finding>>
GetAndMergeDbValues = cells =>
{
var groupings = from opt in cells
from c in opt
group c by (c.TimePeriod, c.Periodicity) into g
select new QueryGrouping
(
g.Key.Item1,
g.Key.Item2,
g
);
...
};
The ctor and data CellData is defined as:
public class CellData
{
public CellData(string sheet,
string range,
string companyId,
string mnemonic,
DateTime timePeriod,
string periodicity,
string value)
{
this.Sheet = sheet;
this.Range = range;
this.CompanyId = companyId;
this.Mnemonic = mnemonic;
this.TimePeriod = timePeriod;
this.Periodicity = periodicity;
this.Value = value;
}
Left out private static constructors methods for brevity’s sake.
Finally QueryGrouping is defined as:
public class QueryGrouping
{
public QueryGrouping(DateTime TimePeriod, string Periodicity, IEnumerable<CellData> Cells)
{
this.TimePeriod = TimePeriod;
this.Periodicity = Periodicity;
this.Cells = Cells;
}
public string Periodicity { get; set; }
public DateTime TimePeriod { get; set; }
public IEnumerable<CellData> Cells { get; set; }
}
Now if i change my function to use validation it looks like this:
public static Func<IEnumerable<Validation<string, CellData>>, IEnumerable<Finding>>
GetAndMergeDbValues = cells =>
{
var groupings = from opt in cells
from c in opt
group c by (c.Success.TimePeriod, c.Success.Periodicity) into g
select new QueryGrouping
(
g.Key.Item1,
g.Key.Item2,
g
);
...
};
I presume I have to explicitly call Success on c because it has two states?
Also I get an error on the contructor of query grouping that it expects IEnumerable<CellData> and I’m passing IEnumerable<Validation<string, CellData>>.
I would expect the Select definition for Validation to only return the good state since this is monadic flow.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 21 (10 by maintainers)
I think I understand your problem. First, I will share my suggestion and then explain why you were having trouble.
Suggestion
In the
Option<>case, I recommend this code:Then in the
Validation<,>case, I recommend reducing to theOption<>case with this code:Explanation
That is true, but the code in your example is not calling
Validation<,>.Select; it is callingIEnumerator<ValidationData<,>>.GetEnumerator, which is defined onIEnumerable<ValidationData<,>>.Each LINQ syntax query can only “unwrap” a single monad (or, more generally, functor). In both of your examples, the single functor in question is
IEnumerable<>. BothOption<>andValidation<,>implementIEnumerable<T>for some typeT. ForOption<A>, we haveT = A. ForValidation<F, S>, we haveT = ValidationData<F, S>. Enumerating over anOption<A>will yield anAit if has one and nothing otherwise. Enumerating overValidation<F, S>will yield exactly oneValidationData<F, S>in the appropriate state and containing the corresponding data.Sort of, but the
Successproperty could contain garbage data if theValidationData<,>instance is in the other state.By looking at your code, I think you are trying to filter out the instances of
Option<>andValidation<,>that are not in the “good” state and then mapping the remainingCellDatainstances toQueryGroupinginstances. (In particular for yourOption<>case, you start withcellsof typeIEnumerable<Option<CellData>>and end withgroupingsof typeIEnumerable<QueryGrouping>.) That is exactly what my suggestions do.