Solving the game Set in F#
Well, you're off to a good start, I think. Only one major thing comes to mind, when I read your code.

Tuples

Instead of operating on seqs or similar, use a tuple. The size of a tuple is fixed and known at compile time. In this game, you know you'll always consider three cards at a time, so it fits the bill. This will also help simplify your allEqual and allDifferent functions. The isSet function still works, as the parameter l is now a tuple instead of a seq.

let allEqual (c1, c2, c3) = c1 = c2 &amp;&amp; c2 = c3
let allDifferent (c1, c2, c3) = c1 &lt;&gt; c2 &amp;&amp; c2 &lt;&gt; c3 &amp;&amp; c1 &lt;&gt; c3


This affects the shape of your compare function as well. The line

let colorSet = cardList |&gt; List.map (fun c -&gt; c.Color  ) |&gt; isSet


now becomes like

let colorSet = isSet (card1.Color, card2.Color, card3.Color)


and similar for shapeSet, patternSet and numsSet. Now the cardList variable may be removed, and the compare function is short and to the point.

Abstracting the isSet function

Suppose you think the way the colorSet, shapeSet, etc. variables are defined looks to clunky. You could abstract away the commonalities, by defining a function for getting the Color property and so on. These could then be supplied as arguments to the isSet, allEqual and allDifferent functions . Like this:

let color c = c.Color
// ...
let allEqual feature (c1, c2, c3) = feature(c1) = feature(c2) &amp;&amp; feature(c2) = feature(c3)
// ...
let cards = (card1, card2, card3)
let colorSet = isSet color cards
// ...


I've only shown a couple of the required functions above, but I hope you get the point. In a small example like this, this might be overkill, but had you had many more features, I would probably go that way.

Discriminated unions

One last point is, that it would be obvious to use discriminated unions instead of string and int. I.e. you could define types for each feature, and use them in the Card definition

type Color = Green | Blue | Red
type Number = One | Two | Three
// ...
type Card = { Color: Color; Number: Number; ... }


This will help readability of your code. Furthermore, if this should interact with the outside would, where input comes in the shape of strings, it pushes parsing and validation to the boundary layer.