Another twist on Type Providers - f#

Trying to extend the boundary of the usage of type provider, I figured I could use :
//Does not work
let exceldatatype = MyExcelTypeProvider.ExcelFile<filename="Brokernet.xls">
let file = new exceldatatype()
let f1(elem:exceldatatype .Row) =
elem.BID
this works though :
//Works
let file= MyExcelTypeProvider.ExcelFile<filename="Brokernet.xls">()
let f1(elem:MyExcelTypeProvider.ExcelFile<filename="Brokernet.xls">.Row) =
elem.BID
This does not work either :
//Does not work
let typealias = MyExcelTypeProvider.ExcelFile<filename="Brokernet.xls">.Row
I guess there is some deep lesson to be found there about runtime and compile time properties, but I am not sure what.
UPDATE
As specified by the ever helpful kvb, the following works :
type typealias = MyExcelTypeProvider.ExcelFile<filename="Brokernet.xls">
let file2 = new typealias()

In your first line, try type ... = ... instead of let ... = ....

Related

Cannot convert ZoneConfiguration to ZoneOptions

As ZoneOptions is deprecated, I changed optionsByRecordZoneID variable to ZoneConfiguration as follows
var optionsByRecordZoneID = [CKRecordZone.ID: CKFetchRecordZoneChangesOperation.ZoneConfiguration]()
for zoneID in zoneIDs {
let options = CKFetchRecordZoneChangesOperation.ZoneConfiguration()
options.previousServerChangeToken = settings.getChangeToken(forKey: databaseTokenKey)
optionsByRecordZoneID[zoneID] = options
}
Now, I am getting the following error for this line for optionsByRecordZoneID variable,
let fetchRecordZoneChangesOperation = CKFetchRecordZoneChangesOperation(recordZoneIDs: zoneIDs, optionsByRecordZoneID: optionsByRecordZoneID)
Cannot convert value of type '[CKRecordZone.ID :
CKFetchRecordZoneChangesOperation.ZoneConfiguration]' to expected
argument type '[CKRecordZone.ID :
CKFetchRecordZoneChangesOperation.ZoneOptions]?'
Any help in regard to get rid of it would be appreciated.
The init(recordZoneIDs:,optionsByRecordZoneID:) is deprecated too since it takes the old ZoneOptions.
Use init(recordZoneIDs:,configurationsByRecordZoneID:).
let fetchRecordZoneChangesOperation = CKFetchRecordZoneChangesOperation(recordZoneIDs: zoneIDs, configurationsByRecordZoneID: optionsByRecordZoneID)
Just add this entry to state that the accepted answer it is the way to do it in Xcode 10.2. Please take a look at it.

`CountedSet` initialization issue

I'm comparing the characters contained within two words. In seeking to accomplish this, Set (aka NSSet) seemed like the way to go to accomplish this task. I've discovered it returns false positives on matches, so I am attempting to use CountedSet (aka NSCountedSet) instead.
I'm able to initialize a Set without issue, but I can't get the CountedSet initializer to work. Here's what I've done...
I start with a String:
// Let's say myTextField.text = "test"
let textFieldCharacters = myTextField.text?.characters
// word is a string from the ENABLE list of words
let wordCharacters = word.characters
Then I dump the characters into an Array:
var wordCharactersArray = [Character]()
for character in wordCharacters {
wordCharacterArray.append(character)
}
var textFieldCharactersArray = [Character]()
for character in textFieldCharacters {
wordCharacterArray.append(character)
}
Then I create a Set from the character arrays:
let textFieldSet = Set<Character>(textFieldCharactersArray)
let wordSet = Set<Character>(wordCharactersArray)
Finally, I test to see if the textFieldSet is a superSet of wordSet with the following:
textFieldSet.isSuperset(of: wordSet)
Going back to my example, if myTextField.text is "test", I'm returning values for word whose characters are a superset of the wordSet, but the counts of the individual elements don't match the character counts of myTextField.text
In researching my issue, I've found CountedSet (fka NSCountedSet), which I think would resolve my issue. It has two method signatures:
public convenience init(array: [AnyObject])
public convenience init(set: Set<NSObject>)
I've tried initializing the 2 sets of characters like so:
let textFieldSet = CountedSet(array: textFieldCharacterArray)
let wordSet = CountedSet(array: wordCharacterArray)
I get the following error for the sets
Cannot convert value of type '[Character]' to expected argument type
'[AnyObject]'.
So I tried initializing the set like this:
let textFieldSet = CountedSet(array: textFieldCharacterArray as! [AnyObject])
Which yields the following error:
'AnyObject' is not a subtype of 'Character'
I've also tried to initialize the CountedSet with a Set, per the method signature, but I get errors when I try to do that, too.
Any suggestions how to initialize a CountedSet would be greatly appreciated.
You are correct that if you need to compare not just the presents of elements but also their count, you should use CountedSet, which is a renaming of NSCountedSet for swift 3.0. The problem you are running into is CountedSet can only accept elements that are objects and Characters are not. As Eric D points out in their comment, the easies way to get around this is by mapping your [Character] to [String] which will bridge to [NSString].
You are not running into this problem using Set, because it is a native Swift collection type that initialize with elements of any type. This is why you can initialize a Set with [Character].
To see the difference:
let word = "helo"
let wordCharacters = Array(word.characters)
let wordSet = Set(wordCharacters)
let wordCharStrings = wordCharacters.map{String($0)}
let wordCountedSet = CountedSet(array: wordCharStrings)
let textField = "hello"
let textFieldCharacters = Array(textField.characters)
let textSet = Set(textFieldCharacters)
let textFieldCharStrings = textFieldCharacters.map{String($0)}
let textFieldCountedSet = CountedSet(array: textFieldCharStrings)
textFieldCountedSet.isSubset(of: wordCountedSet as! Set<NSObject>) // returns false, but if word had two or more l's it would return true
textSet.isSubset(of: wordSet) // returns true

F# Discriminated Union Type Issue

I'm having a problem getting my DU working as expected. I've defined a new DU which either has a result of type <'a> or any Exception derived from System.Exception
open System
// New exceptions.
type MyException(msg : string) = inherit Exception(msg)
type MyOtherException(msg : string) = inherit MyException(msg)
// DU to store result or an exception.
type TryResult<'a, 't> =
| Result of 'a
| Error of 't :> Exception
//This is fine.
let result = Result "Test"
// This works, doing it in 2 steps
let ex = new MyOtherException("Some Error")
let result2 = Error ex
// This doesn't work. Gives "Value Restriction" error.
let result3 = Error (new MyOtherException("Some Error"))
I can't understand why it is allowing me to create an "Error" if I do it in 2 steps, but when i'm doing the same thing on a single line, I get a Value Restriction error.
What am i missing?
Thanks
UPDATE
Looking at the post by #kvb, adding type information each time I need to create an Error seemed a bit verbose, so I wrapped it up into an additional method which creates an Error and is a bit more succinct.
// New function to return a Result
let asResult res : TryResult<_,Exception> = Result res
// New function to return an Error
let asError (err : Exception) : TryResult<unit,_> = Error(err)
// This works (as before)
let myResult = Result 100
// This also is fine..
let myResult2 = asResult 100
// Using 'asError' now works and doesn't require any explicit type information here.
let myError = asError (new MyException("Some Error"))
I'm not sure if specifying an Error with 'unit' will have any consequences I haven't foreseen yet.
TryResult<unit,_> = Error(err)
Consider this slight variation:
type MyOtherException(msg : string) =
inherit MyException(msg)
do printfn "%s" msg
let ex = new MyOtherException("Some Error") // clearly, side effect occurs here
let result2 = Error ex // no side effect here, but generalized value
let intResults = [Result 1; result2]
let stringResults = [Result "one"; result2] // can use result2 at either type, since it's a generalized value
let result3 = Error (MyOtherException("Some Error")) // result would be of type TryResult<'a, MyOtherException> for any 'a
// In some other module in a different compilation unit
let intResults2 = [Result 1; result3] // why would side effect happen here? just using a generic value...
let stringResults2 = [Result "one"; result3] // likewise here...
The issue is that it looks like result3 is a value, but the .NET type system doesn't support generic values, it only supports values of concrete types. Therefore, the MyOtherException constructor needs to be called each time result3 is used; however, this would result in any side effects occurring more than once, which would be surprising. As Ringil suggests, you can work around this by telling the compiler to treat the expression as a value anyway:
[<GeneralizableValue>]
let result3<'a> : TryResult<'a,_> = Error(new MyOtherException("Some Error"))
This is fine as long as the constructor doesn't have side effects.
You can do:
let result3<'a> = Error (new MyOtherException("Some Error"))
EDIT:
As for why you can't do it in one step, first note that this results in the same error:
let result4 = Result (new MyOtherException("Some Error"))
As does this:
let result4 = Result ([|1;|])
But that this works:
let result4 = Result ([1;])
What's similar about Exception and Arrays, but not Lists? It's their mutability. The value restriction will bother you when you try to do make a TryResult with a type that is mutable in a single step.
Now as for why the two step process solves this, it's because the constructor make the whole function not generalizable because you're applying a function to the constructor. But splitting it into two steps solves that. It is similar to Case 2 here on MSDN.
You can read more about it at the above MSDN article and the why this happens in this more indepth blog post.

SQLite.Swift: Cannot invoke 'insert' with an argument list of type '(Setter, Setter, Setter)'

Okay, after some trial and error, I managed to eliminate some of my other errors, although I still have an issue with one command returning the above error. The line is:
PCharacter.PCharacters.insert(PCharacter.charName <- "\(newCharName)",
PCharacter.maxHP <- "\(newCharHP)", PCharacter.maxMP <- "\(newCharMP)")
As far as I can tell, this follows the format of the insert command, except the example on Github uses hard coded values, rather than variables, although I need the variables since the user inputs them.
Just to give a little bit more background: PCharacter is a struct in AppDelegate, while this is a command contained in an Action linked to a button in the ViewController.
Here's the PCharacter struct:
struct PCharacter {
static let PCharacters = db["PCharacters"]
static let id = Expression<Int64>("id")
static let charName = Expression<String>("charName")
static let currentHP = Expression<Int64>("currentHP")
static let maxHP = Expression<Int64>("maxHP")
static let currentMP = Expression<Int64>("currentMP")
static let maxMP = Expression<Int64>("maxMP")
static let currentExp = Expression<Int64>("currentExp")
static let nextExp = Expression<Int64>("nextExp")
static let charWeaponID = Expression<Int64>("charWeaponID")
static func createTable() {
db.create(table: PCharacters) { t in
t.column(id, primaryKey: .Autoincrement)
t.column(charName, unique: true)
t.column(currentHP)
t.column(maxHP)
t.column(currentMP)
t.column(maxMP)
t.column(currentExp)
t.column(nextExp)
t.foreignKey(charWeaponID, references: Weapon.Weapons[id], delete: .SetNull)
}
}
}
Thanks for any help!
There is a section of the Contributing Guidelines that covers this exact error. If you split your insert over multiple lines, you’ll tease away the right error message on the following 2 lines:
PCharacter.maxHP <- "\(newCharHP)"
PCharacter.maxMP <- "\(newCharMP)"
Binary operator '<-' cannot be applied to operands of type 'Expression' and 'String'
Your maxHP and maxMP columns are Int64, but you're setting them to be string values. Ensure that newCharHP and newCharMP are both Int64.

CMVideoFormatDescriptionGetCleanAperture() swift error

I can't get the CMVideoFormatDescriptionGetCleanAperture() function to work. Using
var videoDescriptionRef = port.formatDescription as CMVideoFormatDescriptionRef
var cleanAperture = CMVideoFormatDescriptionGetCleanAperture(videoDescriptionRef, true)
or
var cleanAperture = CMVideoFormatDescriptionGetCleanAperture(port.formatDescription, true)
gives me the following errors, respectively:
Cannot convert expression's type 'CMVideoFormatDescriptionRef' to type 'CMVideoFormatDescriptionRef'
And the second is
Could not find an overlad for '__conversion' that accepts the supplied arguments
Does anyone know how to fix these or can anyone point out any errors in getting the format description for retrieving the clean aperture?
CMFormatDescription itself does not have a member takeUnretainedValue. It is a member of Unmanaged<T>. You need to define an unmanaged variable first, get a value into it and then you retain it.
As I do not know how you created port.formatDescription, here is an example where formatDescription is created from PPS/SPS from an AVC video.
// create the receiving unmanaged variable
var formatDescription: Unmanaged<CMVideoFormatDescription>?
// call the not annotated method, this method will fill in formatDescription which is Unmanaged<T>
let result = CMVideoFormatDescriptionCreateFromH264ParameterSets(nil, UInt(parameterSets.count), parameterSets, parameterSetSizes, 4, &formatDescription)
// check result, yada yada yada before continuing
// now we can actually retain the value
let formatDescriptionRef = formatDescription!.takeUnretainedValue() as CMVideoFormatDescriptionRef
// and we can do what ever we want with it in Swift without caring anymore.
var cleanAperture = CMVideoFormatDescriptionGetCleanAperture(formatDescriptionRef, 1)
Create an unmanaged type
Use this unmanaged type in an not annotated method
Retain the value
Work with it without thinking about how you created it.
So adjust your code where you create the port.formatDescription as a Unmanaged and you should be good.
Try to use .takeUnretainedValue() like this:
var videoDescription : CMVideoFormatDescription = port.formatDescription.takeUnretainedValue()
var cleanAperture = CMVideoFormatDescriptionGetCleanAperture(videoDescription, true)

Resources