haskell / haskell/haskell-language-server
Split a selected variable or underscore pattern
- Dominant language
- Haskell
- Stars
- 3k
- Forks
- 455
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 12
Description
This is a suggestion to extend the case split plugin (which I'm very excited about) to support splitting a hovered variable or underscore pattern (which could be nested in a larger pattern). This could be applied in both nested and multi-pattern scenarios e.g. function definitions (top-level, let, where) and \cases - the LHS and RHS would be copied wholesale (apart from the pattern which is split). So it relates to #5068 but doesn't fully address it (e.g. the case of an existing incomplete function, or introducing lambdas/`\case`[`s`] to introduce the variables to split on).
Example - splitting `_` inside `Just _` on the first line here:
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just _) = putStrLn "example"
fun _ _ = pure ()
```
would produce
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just False) = putStrLn "example"
fun (x:xs) (Just True) = putStrLn "example"
fun _ _ = pure ()
```
I'm not sure how difficult this is, but it would be very useful. Here's a hack for doing it via the existing plugin with manual touchups.
1. If the pattern is _, give it a unique name
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just uq123) = putStrLn "example"
fun _ _ = pure ()
```
2. Replace the RHS with an empty `case of`
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just uq123) = case uq123 of -- remember RHS = putStrLn "example"
fun _ _ = pure ()
```
3. Complete the case of
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just uq123) = case uq123 of -- remember RHS = putStrLn "example"
False -> _
True -> _
fun _ _ = pure ()
```
4. Replace the RHS of every branch from 3 with the old one
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just uq123) = case uq123 of
False -> putStrLn "example"
True -> putStrLn "example"
fun _ _ = pure ()
```
5. Inline the case of into the outer pattern match, duplicating the LHS as necessary
```Haskell
fun :: String -> Maybe Bool -> IO ()
fun (x:xs) (Just False) = putStrLn "example"
fun (x:xs) (Just True) = putStrLn "example"
fun _ _ = pure ()
```
In terms of utility, 4 is not *that* useful but I can't think of a better behaviour and I think it's slightly more useful than just replacing it with `_`. User beware if the RHS is a huge do-block (in future this could maybe do something intelligent with let or where, or it could just have a cutoff and put `_` in all but one branches). 5 could be its own refactoring action but I'm not sure how likely a user is to actually need it.
I am not sure if there are any possible issues with GADTs and existentials here as I know pattern match order can matter.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reading the existing case split plugin and comparing its behavior with issue #5068. Define how splitting a hovered variable or nested underscore pattern should work across function definitions and cases, including GADTs and existentials; done means the selected pattern is split while the surrounding LHS and RHS are preserved as described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- haskell
- Domain
- devtools
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100