I'm trying to do the following, but the compiler exits with code 1.
exception InvalidCharacter
fun order (_, _, nil) = nil
| order(b:char list, l::xl::xxl, s::xs) = if s=l then length(l::xl::xxl)::(order (b, b, xs))
else order(b, xl::xxl, s::xs)
| order (_, nil, _) = raise InvalidCharacter;
order ([#"a",#"b", #"c", #"d", #"e"],[#"a",#"b", #"c", #"d", #"e"],[#"b", #"e"]);
And the compiler also gives the match nonexhaustive for this function. I can't understand why.
For the middle argument, you have just matched the cases where the list has at least two arguments and when it is empty. You also need a match for when the list has exactly one element.
Related
I am reading this tutorial https://www.stackbuilders.com/blog/nonsense-getting-started-with-reason-and-reason-react/. One of the problems I am facing is that api.noopschallenge.com is now dead. I replaced the API call to this https://random-word-api.herokuapp.com/word?number=20 This works but returns a Json Array. I have to convert the Json Array to list(string).
I modified the decodeWords function as
let decodeWord = (json: Js.Json.t) : list(string) =>
switch(Js.Json.decodeArray(json)) {
| None => []
| Some(array) => Belt.Array.map(Js.Json.decodeString, array)
};
But this gives me error
This has type:
Js.Json.t => option(Js.String.t) But somewhere wanted:
array('a)
How do I convert the Json Array to list(string)?
Two problems:
You've switched the arguments to Belt.Array.map around.´array` should come first.
Since decodeString returns an option(string) instead of just a string, you'll have to deal with the Nones somehow. Using Belt.Array.keepMap is a shorter way of just ignoring them.
let decodeWords = (json: Js.Json.t): list(string) =>
switch (Js.Json.decodeArray(json)) {
| None => []
| Some(array) =>
array->Belt.Array.keepMap(Js.Json.decodeString)->Belt.List.fromArray
};
But using the Js.Json API directly is rather cumbersome. You might want to consider using a third-party json decoding library such as bs-json (disclaimer: authored by me) instead. Then it would be as simple as:
let decodeWords = Json.Decode.(list(string))
Or, if you still want it to return an empty list instead of raising an exception on decode failure:
let decodeWords = Json.Decode.(withDefault([], list(string)))
I think I resolved it myself. but if you know of a better solution then please let me know
let decodeWords = (json: Js.Json.t) : list(string) =>
switch(Js.Json.decodeArray(json)) {
| None => []
| Some(array) => Belt.Array.reduce(array, [], (acc, value) => {
switch(Js.Json.decodeString(value)) {
| None => acc
| Some(v) => [v, ...acc]
}
})
};
I am trying to find out the count of first and last name value exit in an array of a and return a result as[String: Int] a count with the same key.
I am getting error on this line newResult[arg.key] = counts . Cannot assign value of type 'Int' to type 'Int?
func abbreviation(a:[String], b: [String : String]) ->[String : Int] {
let dict = b.reduce([String : Int]()){ (result, arg) in
var newResult = result
let counts = a.reduce(0) { (newcount, value) -> Int in
let count = newcount + (value.components(separatedBy:arg.value).count - 1)
return count
}
return newResult[arg.key] = counts
}
return dict
}
//result
let dict = abbreviation(a:["This is chandan kumar and chandan kumar and new chandan","check chandan kumar","non ame"], b:["first":"chandan","last":"kumar"])
The error message is so confusing, and you may need to be accustomed to take it as Swift cannot infer some types in this context.
With this line:
return newResult[arg.key] = counts
Do you know what is returned with this return-statement? It's a Void, also known as an empty tuple. (Void is the result type of assignment statement in Swift.) You might have expected newResult would be the result of the closure, but that sort of things would not happen unless you explicitly write return newResult.
Try changing the line in to the following:
newResult[arg.key] = counts
return newResult
You are trying to return the result of an assignment expression:
return newResult[arg.key] = counts
or maybe you are trying to assign to the result of a return statement? This line doesn't make sense which way you look at it. You should separate the two things you are doing:
newResult[arg.key] = counts
return newResult
It seems like in this situation, you should use the other overload of the reduce method - reduce(into:_:).
The reduce method you are currently using requires you to return a new value every time, but you are just adding a KVP to a dictionary i.e. modifying an existing value. This means that you are creating lots of copies of dictionaries. This is a good sign that reduce(into:_:) might be a better fit.
func abbreviation(a:[String], b: [String : String]) ->[String : Int] {
// notice the parameter label "into:"
let dict = b.reduce(into: [String : Int]()){ (result, arg) in
let counts = a.reduce(0) { (newcount, value) -> Int in
let count = newcount + (value.components(separatedBy:arg.value).count - 1)
return count
}
result[arg.key] = counts // with reduce(into:_:), you don't return anything, just modify the first argument
}
return dict
}
I'd like to test if a number (n) or more elements of a Sequence or Collection will return true when passed to a function. I'm not interested in how many elements would return true, just if n or more would or would not. I can get the correct result with this code:
let result = collection.filter { test($0) }.count > (n-1)
But the test function is called once for each element of collection. Is there a better (or possibly 'lazy') way to do this?
I can do this manually but iterating over the collection something like:
let result:Bool = {
var nCount = 0
for object in collection {
if test(object) {
nCount = nCount + 1
if nCount >= n {
return true
}
}
}
return false
}()
But the first way seems a lot more elegant.
I understand that, in a worst-case scenario, every element would have to be tested. I'm just like to avoid the unnecessary computation if possible.
In the case n=1 (check if at least one element of the sequence passes
the test) you can use contains(where:) with a predicate:
let result = sequence.contains(where: { test($0) } )
or just
let result = sequence.contains(where: test)
In the general case (check if the sequence contains at least a given number of matching items) you can use a lazy filter. Example:
func isEven(_ i : Int) -> Bool { return i % 2 == 0 }
let numbers = Array(1...10)
let atLeast4EvenNumbers = !numbers.lazy.filter(isEven).dropFirst(3).isEmpty
print(atLeast4EvenNumbers)
If you add a print statement to the isEven function then you'll see
that it is not called more often than necessary.
Lets say I have two variables, both optionals:
var a:Int? = 42
var b:Int? = 13
I have a condition where it's OK to proceed as long as these are not BOTH currently nil. I thoughtlessly put together something like:
guard let _ = a, let _ = b else { return }
I was absentmindedly thinking the conditions would be OR'ed, rather than AND'ed. Obviously that was wrong. The question then becomes, is there an idiomatic/preferred way to test that? Or do I just regress to the basics:
if a == nil && b == nil { return }
Aside
If I use the message extensions added by this post, then I might happily write something like
guard a.notNil || b.notNil else { return }
Which is about is close as I can come to "make certain (guard) that a is not nil or b is not nil"
A guard is an if, really, so you can do this the same way. This is clear and uses guard, which seems to be part of the fun. I present OR and AND options so you can pick one.
func doItOr(a: Int?, b:Int?) {
guard (a != nil || b != nil) else { return }
print("either A and B is not nil");
}
func doItAnd(a: Int?, b:Int?) {
guard (a != nil && b != nil) else { return }
print("both A and B are not nil");
}
doItOr(nil, b: nil)
doItOr(nil, b: 5)
doItOr(4, b: 5) // prints
doItAnd(nil, b: nil)
doItAnd(nil, b: 5)
doItAnd(nil, b: nil)
doItAnd(4, b: 5) // prints
it's OK to proceed as long as these are not BOTH currently nil
Your question poses two quite different possible conditions, so I will assume, for purposes of discussion, that you mean this one, namely "not both currently nil". Okay, then: "Not" is !. "Both" is &&. So, like this:
guard !(a == nil && b == nil) else {return}
If you really don't need to bind a or b as non-optionals or discern which of the two is non-nil, I believe the idiomatic approach would still be to use the if statement.
I generally use guard to narrow the specificity of my parameters by binding optionals, downcasting, etc.
You don't seem to be interested in doing that here. You just want to check them, so if seems to appropriately express that.
I have a C function called Foo_C_Func, which I need to use as a callback. The rest of the app is coded in Swift. As I understand it, the following code should work, but instead I get a compiler error.
// typealias makes our function signature easier to read
typealias Sig = ( EventHandlerCallRef, EventRef, UnsafeMutablePointer<Void>) -> OSStatus
// We need to make a CFunctionPointer to the C function
var ptr = UnsafeMutablePointer<Sig>.alloc(1)
ptr.initialize( Foo_C_Func )
let c_ptr = COpaquePointer( ptr )
let proc_ptr = CFunctionPointer<Sig>( c_ptr ) as EventHandlerProcPtr
// now we should be able to create the EventHandlerUPP
let handler_upp = NewEventHandlerUPP( proc_ptr )
Trying to Build this fails with the following error:
Undefined symbols for architecture x86_64:
"_Foo_C_Func", referenced from:
__TTOFSC10Foo_C_FuncFTVSs14COpaquePointerS_GVSs20UnsafeMutablePointerT___VSs5Int32 in Demo.o
"_NewEventHandlerUPP", referenced from:
__TFC17DemocfMS0_FT_S0_ in Demo.o
ld: symbol(s) not found for architecture x86_64
I also notice when I hover over the last line, that the Xcode tooltip shows the return type of NewEventHandlerUpp to be (EventHandlerProcPtr) rather than EventHandlerProcPtr.
Am I doing it wrong, or is it impossible to create an EventHandlerUPP within Swift?
I'm posting this for user MAH, though I have abandoned the original project. The following code compiles in Swift 3. I haven't check whether it works beyond that.
import Carbon
func hotkey_callback( _:EventHandlerCallRef?, _ event:EventRef?, _ context:UnsafeMutablePointer<Void>? ) -> OSStatus {
// Do stuff
return noErr
}
let handler_ref_ptr = UnsafeMutablePointer<EventHandlerRef?>( allocatingCapacity: 1 )
let spec_ptr = UnsafeMutablePointer<EventTypeSpec>( allocatingCapacity: 1 )
spec_ptr.pointee = EventTypeSpec( eventClass: OSType( kEventClassKeyboard ), eventKind: UInt32( kEventHotKeyPressed ) )
let hotkey_callback_pointer = hotkey_callback as! EventHandlerUPP
let status = InstallEventHandler( GetEventDispatcherTarget(), hotkey_callback_pointer, 1, spec_ptr, nil, handler_ref_ptr )
Here's an alternate answer, if you're using Swift 3. Swift 2 is different than Swift 3, in that the former sucks, whereas the latter is usable.
let hotkey_callback: EventHandlerUPP = { _, _, _ in
// Do stuff
return noErr
}
var handler: EventHandlerRef? = nil
var spec = EventTypeSpec(
eventClass: OSType(kEventClassKeyboard), eventKind: UInt32(kEventHotKeyPressed)
)
let status = InstallEventHandler(
GetEventDispatcherTarget(), hotkey_callback, 1, &spec, nil, &handler
)
Note that we can use "&" to avoid manually allocating pointers now, and note that adhering to the informal "EventHandlerUPP" protocol is now explicit and doesn't require our manually declaring the Type of each argument. So much easier to read :)