Why doesn't this active pattern usage compile?
I receive an error on the following:
match cell1 cell2 with
| CellsAreDifferent -> isValueNeighbor cell1.X cell2.X
&& isValueNeighbor cell1.Y cell2.Y
| CellsAreSame -> false
Type mismatch. Expecting a
Cell -> Choice<'a,'b> but given a
Cell -> Cell -> Choice The type 'Choice<'a,'b>' does not match the type 'Cell -> Choice'
The code is here:
let (|CellsAreSame|CellsAreDifferent|) cell1 cell2 =
match cell1.X <> cell2.X
|| cell1.Y <> cell2.Y with
| true -> CellsAreDifferent
| false -> CellsAreSame
let isNeighbor cell1 cell2 =
let isAbsNeighbor v1 v2 =
match abs (v1 - v2) with
| 0 | 1 -> true
| _ -> false
let isValueNeighbor v1 v2 =
match v1 >= 0
&& v2 >= 0 with
| true -> isAbsNeighbor v1 v2
| _ -> isAbsNeighbor v2 v1
match cell1 cell2 with
| CellsAreDifferent -> isValueNeighbor cell1.X cell2.X
&& isValueNeighbor cell1.Y cell2.Y
| CellsAreSame -> false
I was attempting to reference this documentation.
Here you are trying to match on cell1 cell2.
This doesn't make sense as a value, as it is trying to use a value as a function.
I think the best solution would be to change to a tuple.
Something like
let (|CellsAreSame|CellsAreDifferent|) (cell1, cell2) =
and
match (cell1, cell2) with
Related
This cannot work:
let a () =
async {
return 0
}
let b x =
async {
return
match x with
| true ->
let! y = a() <- you can't compile this
y
| false ->
0
}
I understand I could do this:
let b x =
async {
match x with
| true ->
return! a()
| false ->
return 0
}
but there are cases where I need a:
let! y = a()
to do more operations with the result.
Is there an elegant way to achieve this?
Can't you combine the two?
let b x =
async {
match x with
| true ->
let! y = a()
return y
| false ->
return 0
}
You can move the async expression inside each case:
let b x =
match x with
| true -> async {
let! y = a ()
...
return y
}
| false -> async { return 0 }
I don't know if you think this is more elegant, but more functions usually makes it look a bit nicer, here's an example:
module Async =
let create v = async { return v }
let bind f a = async.Bind (a, f)
let map f a =
bind (f >> create) a
let a () = Async.create 0
let addOne y =
y + 1
let b x =
match x with
| true -> a () |> Async.map addOne
| false -> Async.create 0
// Additional piping to map or bind if you wish, e.g:
// |> Async.bind ...
You can do the return inside the match.
let a () = async {
return 0
}
let b x = async {
match x with
| true -> return! a()
| false -> return 0
}
Otherwise you can do this:
module Async =
let create x = async { return x }
let a () = async {
return 10
}
let b x = async {
let! x1 =
match x with
| true -> a()
| false -> async { return 0 }
let! x2 =
if x then a() else Async.create 0
// Do whatever with x1 or x2
return x2
}
Create a function for code that occur often:
let whatever b a x =
if x then a() else Async.create x
let! y = whatever b a 0
I want to define the expected data type of the elements of a tuple which will be passed to call a function. When I don't define it and let the type inference work it is ok, but in the moment I want to write small functions that are still not called anywhere I don't get how to define the arguments.
This example. I expect description to be a tuple where every of the five elements is a int and then extract each of the parts to work with then.
let setArray (description: int * int * int * int * int) =
let id = fun (i, _, _, _, _) -> i
let startX = fun (_, x, _, _, _) -> x
let startY = fun (_, _, y, _, _) -> y
let width = fun (_, _, _, w, _) -> w
let height = fun (_, _, _, _, h) -> h
let arrayResult = Array2D.init (width + 1) (height + 1) (fun i j -> if i < width && j < height then id)
arrayResult
.fsx(29,45): error FS0001: The type 'int' does not match the type ''a * 'b * 'c * 'd * 'e -> 'd'
For other functions, like I said, type inference works and I can use the pattern matching without problem
let getMaxCoords =
let x = elements |> Seq.map (fun (_, x, _, _, _) -> x) |> Seq.max
let y = elements |> Seq.map (fun (_, _, y, _, _) -> x) |> Seq.max
x, y
What am I doing wrong?
First, the following code block is defining five functions, not five integer values:
let setArray (description: int * int * int * int * int) =
let id = fun (i, _, _, _, _) -> i
let startX = fun (_, x, _, _, _) -> x
let startY = fun (_, _, y, _, _) -> y
let width = fun (_, _, _, w, _) -> w
let height = fun (_, _, _, _, h) -> h
What you probably meant to do is to pass the description tuple into each of these destructuring functions, like so:
let setArray (description: int * int * int * int * int) =
let id = description |> (fun (i, _, _, _, _) -> i)
let startX = description |> (fun (_, x, _, _, _) -> x)
let startY = description |> (fun (_, _, y, _, _) -> y)
let width = description |> (fun (_, _, _, w, _) -> w)
let height = description |> (fun (_, _, _, _, h) -> h)
But there's a much easier way to do this. F# lets you destructure a tuple in the function signature. So you can replace that whole code block with the following:
let setArray (id, startX, startY, width, height) =
That's it! So now your entire function looks like:
let setArray (id, startX, startY, width, height) =
let arrayResult = Array2D.init (width + 1) (height + 1) (fun i j -> if i < width && j < height then id)
arrayresult
And there's one more simplification you can make. Any time you have let x = (some calculation) followed immediately by x as the function's return value, you can get rid of that let and just have the function return (some calculation). Applying that simplification, your function becomes:
let setArray (id, startX, startY, width, height) =
Array2D.init (width + 1) (height + 1) (fun i j -> if i < width && j < height then id)
And you're done! If you really want to specify that id, startX, etc., are all integers, you can do it like this:
let setArray (id : int, startX : int, startY : int, width : int, height : int) =
Array2D.init (width + 1) (height + 1) (fun i j -> if i < width && j < height then id)
I have a UIPageViewControllerDataSource initialised as follows:
[<Register ("FlatImagesPageViewDataSource")>]
type FlatImagesPageViewDataSource() as x =
inherit UIPageViewControllerDataSource()
let mutable isinitialised = false
let mutable flatImages : List<UIImage> = List.Empty
let mutable parentView : UIPageViewController = null
let mutable controllers : List<UIViewController> = List.Empty
let viewControllerAtIndex(index : int) =
let mutable result : UIViewController = null
if flatImages.Length = 0 || index >= flatImages.Length then
result <- null
else
let controller = new FlatImagesContentViewController(new IntPtr())
controller.GetImage <- flatImages.[index]
controller.GetPageIndex <- index
if controllers.Length = 0 then
((controller :> UIViewController )::controllers) |> ignore
int(0) |> ignore
else
let listc = List.toArray controllers
listc.[0] <- (controller :> UIViewController)
controllers <- Array.toList listc
int(0) |> ignore
result <- controller
result
member this.GetParentView
with get() = parentView
and set(value) = (
parentView <- value
controllers <- Array.toList parentView.ViewControllers
)
member this.GetFlatImages
with get() = flatImages
and set(value) = (
flatImages <- value
if not isinitialised then
parentView.View.UserInteractionEnabled <- true
if flatImages.Length > 0 then
let initialcontroller = viewControllerAtIndex(0)
let mutable viewControllers : UIViewController list = []
viewControllers <- initialcontroller::viewControllers
parentView.SetViewControllers(viewControllers |> List.toArray,UIPageViewControllerNavigationDirection.Forward,true,null)
controllers <- viewControllers
isinitialised <- true
else
((controllers.[0]) :?> FlatImagesContentViewController).GetImage <- flatImages.[((parentView.ViewControllers.[0]) :?> FlatImagesContentViewController).GetPageIndex]
)
override x.GetNextViewController(pageViewController : UIPageViewController, contentController : UIViewController) =
let mutable returnController : UIViewController = null
if flatImages.Length > 0 then
let curr_index = (contentController :?> FlatImagesContentViewController).GetPageIndex
Console.WriteLine("Attempting after with index ")
Console.WriteLine(curr_index.ToString())
if curr_index < flatImages.Length - 1 then
returnController <- viewControllerAtIndex(curr_index + 1)
returnController
override x.GetPreviousViewController(pageViewController : UIPageViewController, contentController : UIViewController) =
let mutable returnController : UIViewController = null
if flatImages.Length > 0 then
let curr_index = (contentController :?> FlatImagesContentViewController).GetPageIndex
Console.WriteLine("Attempting before with index ")
Console.WriteLine(curr_index.ToString())
if curr_index > 0 then
returnController <- viewControllerAtIndex(curr_index - 1)
returnController
override x.GetPresentationCount(pageViewController : UIPageViewController) =
Conversions.nint(flatImages.Length)
override x.GetPresentationIndex(pageViewController : UIPageViewController) =
let mutable returnVal = 0
if flatImages.Length > 0 then
returnVal <- (controllers.[0] :?> FlatImagesContentViewController).GetPageIndex
Conversions.nint(returnVal)
This code crashes on the line:
parentView.SetViewControllers(viewControllers |> List.toArray,UIPageViewControllerNavigationDirection.Forward,true,null)
in this code block:
member this.GetFlatImages
with get() = flatImages
and set(value) = (
flatImages <- value
if not isinitialised then
parentView.View.UserInteractionEnabled <- true
if flatImages.Length > 0 then
let initialcontroller = viewControllerAtIndex(0)
let mutable viewControllers : UIViewController list = []
viewControllers <- initialcontroller::viewControllers
parentView.SetViewControllers(viewControllers |> List.toArray,UIPageViewControllerNavigationDirection.Forward,true,null)
controllers <- viewControllers
isinitialised <- true
else
((controllers.[0]) :?> FlatImagesContentViewController).GetImage <- flatImages.[((parentView.ViewControllers.[0]) :?> FlatImagesContentViewController).GetPageIndex]
)
with the following exception:
which I don't understand as I have checked that initialController is definitely not null, therefore I don't understand where this exception is coming from.
I notice when you want to use parentView.SetViewControllers(...) the viewControllers only has one object. How do you construct your UIPageViewController?
If you use UIPageViewControllerSpineLocation.Mid or default UIPageViewControllerSpineLocation(default is Mid), it requires at least two controls when you set its ViewControls.
So you can try to modify initial method like:
new UIPageViewController(UIPageViewControllerTransitionStyle.PageCurl,
UIPageViewControllerNavigationOrientation.Horizontal,
UIPageViewControllerSpineLocation.Min)
What's the difference between my actual union case value and the expected value?
I have the following test:
[<Test>]
let ``black checker jumps to king``() =
let redChecker = { RedChecker.Position= { X=1 ; Y=6 } }
let target = (redChecker, [redChecker])
{ BlackChecker.Position= { X=0 ; Y=5 } } |> jumpRed target
|> fst
|> should equal (BlackKing { BlackKing.Position= { X=2 ; Y=7 } })
Here's the actual result when executing the test operation in the interactive window:
val redChecker : RedChecker = {Position = {X = 1;
Y = 6;};}
val target : RedChecker * RedChecker list =
({Position = {X = 1;
Y = 6;};}, [{Position = {X = 1;
Y = 6;};}])
val it : Checker = BlackKing {Position = {X = 2;
Y = 7;};}
I see that a BlackKing value is returned with xy being (2,7). Thus, I'm verifying in my test that union case value with that specific xy value.
I'm just not seeing why my test is failing.
Any suggestions?
Appendix:
open NUnit.Framework
open FsUnit
(* Types *)
type North = NorthEast | NorthWest
type South = SouthEast | SouthWest
type Direction =
| NorthEast
| NorthWest
| SouthEast
| SouthWest
type Position = { X:int; Y:int }
type BlackChecker = { Position:Position }
type RedChecker = { Position:Position }
type BlackKing = { Position:Position }
type RedKing = { Position:Position }
type Checker =
| BlackChecker of BlackChecker
| RedChecker of RedChecker
| BlackKing of BlackKing
| RedKing of RedKing
type King =
| BlackKing of BlackKing
| RedKing of RedKing
(* Functions *)
let rec remove item list = list |> List.filter (fun x -> x <> item)
let setRowPosition y1 y2 y3 index =
match index with
| x when x < 4 -> { X=x; Y=y1 }
| x when x < 8 -> { X=x-4; Y=y2 }
| _ -> { X=index-8; Y=y3 }
let initializeBlack () =
let setPosition index =
index |> setRowPosition 7 6 5
let blackCheckers = List.init 12 setPosition |> List.map (fun pos -> { BlackChecker.Position= { X=pos.X; Y=pos.Y } })
blackCheckers
let initializeRed () =
let setPosition index =
index |> setRowPosition 0 1 2
let redCheckers = List.init 12 setPosition |> List.map (fun pos -> { RedChecker.Position= { X=pos.X; Y=pos.Y } })
redCheckers
let set (x, y) positions (position:Position) =
match not (positions |> List.exists (fun pos -> pos = { X=x; Y=y })) with
| true -> { X=x; Y=y }
| false -> position
let moveBlack direction positions (checker:BlackChecker) =
let position = checker.Position
match direction with
| North.NorthEast -> { BlackChecker.Position= (positions, position) ||> set ((position.X + 1), (position.Y + 1 )) }
| North.NorthWest -> { BlackChecker.Position= (positions, position) ||> set ((position.X - 1), (position.Y + 1 )) }
let moveRed direction positions (checker:RedChecker) =
let position = checker.Position
match direction with
| South.SouthEast -> { RedChecker.Position= (positions, position) ||> set ((position.X + 1), (position.Y - 1 )) }
| South.SouthWest -> { RedChecker.Position= (positions, position) ||> set ((position.X - 1), (position.Y - 1 )) }
let moveKing direction positions (king:King) =
let position = match king with
| BlackKing bk -> bk.Position
| RedKing rk -> rk.Position
let result = match direction with
| NorthEast -> (positions, position) ||> set ((position.X + 1), (position.Y + 1 ))
| NorthWest -> (positions, position) ||> set ((position.X - 1), (position.Y + 1 ))
| SouthEast -> (positions, position) ||> set ((position.X + 1), (position.Y - 1 ))
| SouthWest -> (positions, position) ||> set ((position.X - 1), (position.Y - 1 ))
match king with
| BlackKing _ -> BlackKing { BlackKing.Position= result }
| RedKing _ -> RedKing { RedKing.Position= result }
let jump target yDirection source =
let updateX value = { X=target.X + value
Y=target.Y + yDirection }
match source with
| position when position.Y + yDirection = target.Y &&
position.X + 1 = target.X -> updateX 1
| position when position.Y + yDirection = target.Y &&
position.X - 1 = target.X -> updateX -1
| _ -> source
let jumpRed ((redChecker:RedChecker), (redCheckers:RedChecker list)) (blackChecker:BlackChecker) =
let yIncrementValue = 1
let maxY = 7
let position = blackChecker.Position |> jump redChecker.Position yIncrementValue
match position with
| pos when pos = blackChecker.Position -> BlackChecker { blackChecker with Position= position }, redCheckers
| pos when pos.Y = maxY -> Checker.BlackKing { BlackKing.Position=position }, redCheckers |> remove redChecker
| _ -> BlackChecker { blackChecker with Position= position }, redCheckers |> remove redChecker
let jumpBlack ((blackChecker:BlackChecker),(blackCheckers:BlackChecker list)) (redChecker:RedChecker) =
let yIncrementValue = -1
let minY = 0
let position = redChecker.Position |> jump blackChecker.Position yIncrementValue
match position with
| pos when pos = redChecker.Position -> RedChecker { redChecker with Position= position }, blackCheckers
| pos when pos.Y = minY -> Checker.RedKing { RedKing.Position=position }, blackCheckers |> remove blackChecker
| _ -> RedChecker { redChecker with Position= position }, blackCheckers |> remove blackChecker
Well this statement
{ BlackChecker.Position= { X=0 ; Y=5 } } |> jumpRed target
|> fst
gives:
val it : Checker = BlackKing {Position = {X = 2;
Y = 7;};}
It is of type Checker. On the other hand:
(BlackKing { BlackKing.Position= { X=2 ; Y=7 } })
gives:
val it : King = BlackKing {Position = {X = 2;
Y = 7;};}
It is of type King. They aren't the same types...
If you want to compare them you need to unwrap the BlackKing type inside the things you want to compare via pattern matching.
I have been working on a function for reducing fractions in Swift, and came across the Euclidean algorithm for finding the greatest common factor (http://en.wikipedia.org/wiki/Euclidean_algorithm)
I converted the pseudo code into swift, but yet I am confused how this is going to give me the greatest common factor if it is returning a which I thought was supposed to be the numerator of the fraction. Any help on this would be greatly appreciated. Thanks!
Pseudocode:
function gcd(a, b)
while b ≠ 0
t := b
b := a mod b
a := t
return a
Swift:
var a = 2
var b = 4
func gcd(a: Int, b: Int) -> Int {
var t = 0
while b != 0 {
t = b
let b = a % b
let a = t
}
return a
}
println("\(a)/\(b)")
Console output: 2/4
When you do this
let b = a % b
you are creating another readonly variable b, which has nothing to do with the variable b from the outside scope. You need to remove both lets inside the loop, and make parameters modifiable by declaring them with var, like this:
func gcd(var a: Int, var b: Int) -> Int {
var t = 0
while b != 0 {
t = b
b = a % b
a = t
}
return a
}
You can call your function like this:
let a = 111
let b = 259
println("a=\(a), b=\(b), gcd=\(gcd(a,b))")
This prints a=111, b=259, gcd=37
Taking #dasblinkenlight's answer and getting rid of t by using tuples for parallel assignment yields:
Swift 2.1:
func gcd(var a: Int, var _ b: Int) -> Int {
while b != 0 {
(a, b) = (b, a % b)
}
return a
}
gcd(1001, 39) // 13
var parameters are deprecated in Swift 2.2 and will be removed in Swift 3. So now it becomes necessary to declare a and b as var within the function:
func gcd(a: Int, _ b: Int) -> Int {
var (a, b) = (a, b)
while b != 0 {
(a, b) = (b, a % b)
}
return a
}
Swift 3 version of answer given by Christopher Larsen
func gcd(a: Int, b: Int) -> Int {
if b == 0 { return a }
return gcd(a: b, b: a % b)
}
Can use a recursive method that just keeps calling itself until the GCD is found.
func gcd(a: Int, b: Int) -> Int {
if b == 0 {
return a
}
let remainder: Int = a % b
return gcd(b, b: remainder)
}
and use like so
let gcdOfSomeNums = gcd(28851538, b: 1183019)
//gcdOfSomeNums is 17657