haskell-servant / haskell-servant/servant

(:<|>) is not Associative

Open
#1,643 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Haskell
Stars
2k
Forks
427
Avg merge
2d 23h
Merged PRs (30d)
5

Description

Hello wonderful servant maintainers,

I guess whether this is actually a bug depends on your expected behaviour, but I wasn't easily able to find the expected behaviour written down anywhere (maybe I just missed it);
Given that `:<|>` is defined in `Servant.API.Alternative` I expected it to be associative, so I was quite surprised when I learned it isn't!

Here's a small reproduction which demonstrates this:

```haskell
type FlatAPI =
("a" :> "b" :> Post '[JSON] Int)
:<|> ("a" :> "b" :> Delete '[JSON] String)
:<|> ("c" :> "d" :> Post '[JSON] Int)
:<|> ("c" :> "d" :> Delete '[JSON] String)

type NestedAPI =
("a" :> "b" :> (Post '[JSON] Int :<|> Delete '[JSON] String))
:<|> ("c" :> "d" :> (Post '[JSON] Int :<|> Delete '[JSON] String))

handlePost :: Handler Int
handlePost = pure 1

handleDelete :: Handler String
handleDelete = pure "hello"

server :: Server FlatAPI
server =
handlePost
:<|> handleDelete
:<|> handlePost
:<|> handleDelete

nestedServer :: Server NestedAPI
nestedServer =
(handlePost :<|> handleDelete) -- < these brackets are required.
:<|> handlePost
:<|> handleDelete
```

I had assumed that `FlatAPI` and `NestedAPI` were equivalent, but it turns out that `NestedAPI` requires you to manually group your server implementations to match the bracketing on your API. Remove the brackets causes it to fail to compile.

If this is expected, that's fine, just letting you know that I got tripped up here 😄

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.