For whatever reason, I cannot use a "for" construct within a query expression. What I get is the following error. The code I just what I picked that used to work -->
"error: This control construct may only be used if the computation expression builder defines a 'For' method"
#r "System.Data.Linq.dll"
#r "FSharp.Data.TypeProviders.dll"
open FSharp.Linq
open FSharp.Data.TypeProviders
[<Literal>]
let connectionString' = #"
data source = ...;
initial catalog = NORTHWND;
Integrated Security = SSPI"
type NorthwndDb =
SqlDataConnection<connectionString', Pluralize = true>
let db' = NorthwndDb.GetDataContext()
let curstomerSortedByCountry =
query { for c in db'.Customers do
sortBy c.Country
select (c.Country, c.CompanyName) }
|> Seq.cache
I was not able to test this with your code snippet (don't have a database to test this against), but I think the kind of error you are reporting would happen if you defined a variable named query somewhere in your code snippet before the query expression. For example:
let query = "oops!"
let curstomerSortedByCountry =
query { for c in [1 .. 10] do
sortBy c
select c }
error FS0708: This control construct may only be used if the computation expression builder defines a 'For' method
The reason for this is that the identifier query in query { .. } is just a variable declared in the standard F# library that has various members including query.For. If you hide this with your own declaration, then the member will not be found.
Related
I'm looking for the best way to propagate model updates to the GUI, using a "classic" (as in: non reactive functional) GUI toolkit: Terminal.GUI. Currently I have this code (simplified):
type Tui(state: StateManager) =
let state = state
let window = Window(bla bla bla)
let lblPath = Label(bla bla bla)
let lstView =
{ new ListView(bla bla bla) with
member this.ProcessKey(k: KeyEvent) =
let updateViews() =
Application.MainLoop.Invoke(fun () ->
this.SetSource model.CurrentState.LstData
lblPath.Text <- ustr model.CurrentState.CurrPath)
match k.Key with
| Key.CursorRight ->
state.changeTheState()
updateViews()
true
| _ -> true }
do
Application.Init()
// add all GUI components: window.add(lblPath), etc
Application.Run()
// XXX repetition of updateViews() above!
Application.MainLoop.Invoke(fun () ->
lstView.SetSource model.CurrentState.LstData
lblPath.Text <- ustr model.CurrentState.CurrPath)
The issue here is that the code to update the view components is duplicated. I believe this is because:
in that ProcessKey method of the ListView object expression I cannot access any external method of the Tui class (this is probably also because F# compiler is one-pass only (?))
outside that method I cannot access the updateView function
Is there a better way of doing this that would avoid code repetition? Am I using the wrong pattern GUI update pattern?
(Complete code is here)
Of course, it doesn't need to be too complicated - refactor your update to just take in a listview parameter:
let updateViews (lstView: ListView) =
Application.MainLoop.Invoke(fun () ->
lstView.SetSource state.CurrentState.LstData
...
)
And inside the member definition, call:
updateViews(this)
And below, you can use updateViews lstView.
When you use an object expression, the type of the expression becomes the type you specify in new <type>, so any type augmentations you do inside won't make it outside. For a more OOP approach, declare an intermediate type:
[<AbstractClass>]
type UpdateableList() =
inherit ListView([||])
abstract member Update: unit -> unit
implement your update logic:
{ new UpdateableList(X = Pos.At(0), Y = Pos.At(2), ...) with
member this.Update() =
...
and in your setup, you have access to a public method:
lstView.Update()
When I have a nullable array/list/hashmap such as
var x: ArrayList<String>? = null
I know can access the element at index 1 like so
var element = x?.get(1)
or I could do it in a unsafe way like this
var element = x!![1]
but why can't I do something like this
var element = x?[1]
what's the difference between getting elements from an array using the first example and the last example, and why is the last example not allowed?
In the first example, you're using the safe call operator ?. to call the get function with it.
In the second example, you're using the [] operator on the non-nullable return value of the x!! expression, which of course is allowed.
However, the language simply doesn't have a ?[] operator, which would be the combination of the two. The other operators offered are also don't have null-safe variants: there's no ?+ or ?&& or anything like that. This is just a design decision by the language creators. (The full list of available operators is here).
If you want to use operators, you need to call them on non-nullable expressions - only functions get the convenience of the safe call operator.
You could also define your own operator as an extension of the nullable type:
operator fun <T> List<T>?.get(index: Int) = this?.get(index)
val x: ArrayList<String>? = null
val second = x[2] // null
This would get you a neater syntax, but it hides the underlying null handling, and might confuse people who don't expect this custom extension on collections.
I have a fairly simple javascript method
(props,propName,componentName) => {
var value = props[propName];
const getOrSpread = name =>
props[name] || props.spread && props.spread[name];
// remainder of function code omitted
}
that is working in javascript land. I'm trying to convert it to fable but either I can get it to have a definitely exists property access to .spread or dynamic access to props[propName] but not both
module JsxHelpers =
type IReactProps =
abstract member spread : obj
let isfuncOrNullPropType (props:IReactProps) (propName:string) componentName =
let propsO :obj = box props
let value:obj = propsO?propName
let valueAttempt2:obj = (box props)?(propName)
// rest of translation not attempted yet
value
where if props is defined as IReactProps, then .spread works, but neither of the two possible let value lines compile.
or props is defined as obj and it says `This expression was expected to have type 'obj' but here has type ''a -> obj'
even the simplest object from the documentation doesn't appear to compile:
let isfuncOrNullPropType (props:obj) (propName:string) =
let value2:obj = props?propName
value2
using "fable-core": "^1.0.0-narumi-905"
You definitely need to put the prop name in parentheses according to the documentation. The compiler error you're getting is because props?(propName) returns type 'a -> obj. Apparently, the dynamic (?) operator returns an Applicable, and from the fable source:
/// DO NOT USE: Internal type for Fable dynamic operations
type Applicable = obj->obj
Perhaps try:
let value : obj = unbox<obj> (props?(propName))
I have a simple function that makes use of the F# power pack to convert a quotation into a linq expression. The function is:
let toLinq (exp : Expr<'a -> 'b>) =
let linq = exp.ToLinqExpression()
let call = linq :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)
I use this function to create expressions that are consumed by a C# library that uses linq to sql to query a database. For example I might build an expression like:
let test = toLinq (<#fun u -> u.FirstName = "Bob"#> : Expr<Account->bool>)
and pass it to a method like:
public IEnumerable<T> Find(Expression<Func<T, bool> predicate)
{
var result = Table.OfType<T>();
result = result.Where(predicate)
var resultArray = result.ToArray();
return resultArray;
}
This was working as designed in verion 1.9.9.9 of the power pack. However it no longer works in the latest version of the power pack. The error I recieve is Method 'Boolean GenericEqualityIntrinsic[String](System.String, System.String)' has no supported translation to SQL.
I took a look at the changes to the power pack and it seems that the linq expression that is built using the new version makes use of GenericEqualityIntrinsic for comparing the property's value with the constant, whereas in version 1.9.9.9 it made use of String.op_Equality for comparison.
Is this a correct understanding of the issue? How do I make use of the new version of the power pack to convert quotations to linq expressions that can be consumed by a c# library that uses linq to sql?
Does explicitly calling
System.String.op_Equality(s1,s2)
work?
You can try the quotation as:
<#fun u -> u.FirstName.Equals("Bob")#>
I use this code to execute a python expression using IronPython.
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
scope.SetVariable("m", mobject);
string code = "m.ID > 5 and m.ID < 10";
ScriptSource source =
engine.CreateScriptSourceFromString(code, SourceCodeKind.Expression);
source.Execute(scope);
Is there a way to get the produced Expression Tree as c# object, e.g. the BlockExpression
?
IronPython's internal ASTs also happen to be Expression trees, so you just need to get the AST for your code, which you can do using the IronPython.Compiler.Parser class. The Parser.ParseFile method will return a IronPython.Compiler.Ast.PythonAst instance representing the code.
Using the parser is a bit tricky, but you can look at the BuildAst method of the _ast module for some hints. Basically, it's:
Parser parser = Parser.CreateParser(
new CompilerContext(sourceUnit, opts, ThrowingErrorSink.Default),
(PythonOptions)context.LanguageContext.Options);
PythonAst ast = parser.ParseFile(true);
ThrowingErrorSink also comes from the _ast module. You can get a SourceUnit instance like so (c.f. compile builtin):
SourceUnit sourceUnit = context.LanguageContext.CreateSnippet(source, filename, SourceCodeKind.Statements);
You then have to walk the AST to get useful information out of it, but they should be similar (but not identical to) C# expression trees.