简体   繁体   中英

How do I define infix functions in Haskell?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM