I use VS 2010. This
let b =
let a: int option = None
a.Value
gives me a nice NullReferenceException in the debugger, as expected.
Now try this one:
type A = B
let b2 =
let a: A option = None
a.Value
I get 'No source Available' window in the debugger instead. Why? And how to make it work correctly?
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()
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.
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'm having trouble converting optional input String to Int in order to do calculations on it.
let odoField = UITextField() // allows entry of text to iOS field
odoField.text = "12500" // simulated input
let odoString = odoField.text
// now here is where I get trouble...
if let odoInt = odoString.toInt() {
distance = Double(odoInt)
}
Apparently the toInt suffix is no longer part of Swift. I have tried the following:
if let odoInt = Int(odoString)() {
But then I get the error "Optional type String? is not unwrapped" and a suggestion to put a ! or ?, as in:
if let odoInt = Int(odoString!)() {
But then I STILL get the euro about unwrapping, with the suggestion that I add yet another !, then when I do that, another error that I get rid of the parens, like this:
if let odoInt = Int(odoString!)! {
And then I get ANOTHER error that "Initializer for conditional binding must have Optional type, not 'Int'."
I'm trying to create conditional unwrapping, here.
Help!
First thing to understand is that UITextField.text returns an optional string, so in your code, odoString is of type String?. Also, keep in mind that the Int constructor takes a String, not a String? so you have to unwrap the String? before you can use it. Just putting a ! after the variable (as in Int(odoString!)) will crash your app if the odoString is nil. Better would be something like this:
if let s = odoString, odoInt = Int(s) {
// odoInt is of type Int. It is guaranteed to have a value in this block
}
I've tested Daniel T's answer and it worked.
I have a situation where I want to get the result of a text field back as an optional Int. You can extend this to cover your case using the following code:
let odoInt = odoField.text != nil ? Int(odoField.text!) : nil
if let odoInt = odoInt {
// Use unwrapped odoInt here
}
Another option - for a more compact solution - is to use a flatMap:
let number = odoString.flatMap { Double($0) } ?? 0.0
In fact, it appears that the answer in Swift 2 (Xcode 7 beta 6) is simpler than anything above. The code does not choke on a nil value for odoString when I do e.g. the following:
if let odoInt = Int(odoString!) {
distance = Double(odoInt)
}
I therefore surmise, barring deeper knowledge to the contrary, that the compiler does treat this as "if the statement is True (the right side is valid), then define and initialize the variable, and continue with execution." I welcome further feedback. This does render unnecessary a lot of the extra code that is suggested above.
From what I have learned, to use P/Invoke in F#, the function signature has to be declared first using DllImport like this:
[<DllImport("kernel32.dll", EntryPoint="CopyFile")>]
extern bool copyfile(char[] lpExistingFile, char[] lpNewFile, bool bFailIfExists);
That's all good when the DLL name is known at compile time. How do I interface with an unmanaged C/C++ DLL if I can only discover the name at runtime?
Alternatively, you can come up with a solution that generates PInvoke methods dynamically.
open System
open System.Reflection
open System.Reflection.Emit
open System.Runtime.InteropServices
let assembly = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("PInvokeLibrary"), AssemblyBuilderAccess.Run)
let module_builder = assembly.DefineDynamicModule ("PInvokeLibrary")
let define_dynamic_pinvoke<'d when 'd :> Delegate> (name, library) =
let invoke = typeof<'d>.GetMethod ("Invoke") (* signature of delegate 'd *)
let parameters =
invoke.GetParameters ()
|> Array.map (fun p -> p.ParameterType)
let type_builder = module_builder.DefineType (name, TypeAttributes.Public)
let method_builder =
type_builder.DefinePInvokeMethod (
name,
library,
MethodAttributes.Public ||| MethodAttributes.Static ||| MethodAttributes.PinvokeImpl,
CallingConventions.Standard,
invoke.ReturnType,
parameters,
CallingConvention.Winapi,
CharSet.Ansi)
method_builder.SetImplementationFlags (method_builder.GetMethodImplementationFlags () ||| MethodImplAttributes.PreserveSig)
let result_type = type_builder.CreateType ()
let pinvoke = result_type.GetMethod (name)
Delegate.CreateDelegate (typeof<'d>, pinvoke) :?> 'd
let beep = define_dynamic_pinvoke<Func<int, int, bool>> ("Beep", "kernel32.dll")
beep.Invoke (800, 100)
The native APIs for this are LoadLibrary() and GetProcAddress(). Not sure if there are managed versions of that, but a Google search found something interesting:
Type-safe Managed wrappers for kernel32!GetProcAddress.
Opening line of that is:
Pinvoke is cool in managed code, but sometimes you need to get straight at kernel32!GetProcAddress. For example, maybe you need dynamic control over which unmanaged dll you want to load.
Sounds like what you want to do, no? Rest of the article here.
This problem is not specific to F#. You would need to build a proxy DLL in C++/CLI which will be responsible for loading necessary dll using LoadLibrary function from win API.
I guess it would be better if you could pass the signature of a native F# function to define_dynamic_pinvoke, like define_dynamic_pinvoke<(int * int -> bool)> ("Beep", "kernel32.dll"), but I admit I don't know how to achieve that.
You can rewrite the sample as:
let beep = define_dynamic_pinvoke<delegate of (int * int) -> bool> ("Beep", "kernel32.dll")