I'd like to define a function as infix, so that users don't have to manually surround the function with backticks to call it. Specifically, I'm writing a DSL-like function that accepts a Rank and Suit and contructs a Poker card record:
-- pseudocode
data PokerCard = PokerCard { rank :: Rank, suit :: Suit } deriving (Eq)
of :: Rank -> Suit -> PokerCard
r of s = PokerCard { rank = r, suit = s }
pokerDeck = [
Ace of Spades,
Two of Spades,
...
]
I believe of
is reserved as syntax for case ... of
expressions, so I'd have to rename it something like of'
, .of
, +of
, etc.
There's no way to define a function with an alphanumeric name as infix. Haskell's syntax rules only allow for functions with symbolic names or function names surrounded with backticks to be used infix - there's no way to change that.
Well, you might already know this, but (of course) operators /can/ be infix. So you could , instead r of s
have r >| s
r >| s
.
Here's a hacky solution with some extra typing, but without backticks! I first posted this on reddit, if that's okay.
I assume you have derived Enum
for Rank
.
data OF = OF
ace :: OF -> Suit -> PokerCard
ace _ s = PokerCard Ace s
-- or point-free
two :: OF -> Suit -> PokerCard
two _ = PokerCard Two
-- or with const
three :: OF -> Suit -> PokerCard
three = const (PokerCard Three)
-- you get the idea!
-- the rest in one line:
four,five,six,seven,eight,nine,ten,jack,king :: OF -> Suit -> PokerCard
[four,five,six,seven,eight,nine,ten,jack,king] = map (const . PokerCard) [Four .. King]
-- now you can write
pokerDeck = [
ace OF Spades, two OF Spades -- and so on
]
The OF datatype isn't strictly necessary, but prevents confusing (but very metal) stuff like ace "Motorhead" Spades
. You can still write ace undefined Spades
, there's really no way around that, I think.
If of
wasn't a keyword, you could even write of = OF
.
There is also an utterly evil hack to get rid of the 'of' entirely, and using numbers for cards:
{-# LANGUAGE FlexibleInstances #-} -- this goes on top of your file
instance Num (Rank -> Suit) where
fromInteger n = (undefined : map Card[Ace .. King]) !! (fromInteger n)
Now 2 Spades :: Card
typechecks (but you need the explicit type!) and is what you think it is :-) However, I strongly advise you to not do this in serious code; but it looks kind of cool.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.