Question Details

No question body available.

Tags

haskell functional-programming pattern-matching abstraction pattern-synonyms

Answers (2)

March 9, 2026 Score: 2 Rep: 2,846 Quality: Low Completeness: 80%

To show that sometimes what you ask for is not what you want ... here's a 'solution':


{-# LANGUAGE PatternSynonyms, ViewPatterns  #-}

type Foo = (String, String, String, String) -- override the data Foo decl []

pattern Foo :: Foo -> Bar pattern Foo abcd abcd) -- [] where Foo (a, b, c, d) = Bar (\b1 i b2 -> "function of a, b, c, d, b1, i, b2 hardcoded in the library")

-- example to show uses, types inferred by GHCi let x = (Foo undefined) in x :: Bar -- example build let ff x@(Foo _) = x in ff (Bar undefined) :: Bar -- example match

Obviously I don't want to break the existing call sites,

The existing call sites are using type Foo, not just constructor Foo (and you don't know what's calling that code/where type Foo might appear all over that code). So [] this 'solution' only works because the existing Foo is a simple type that can be declared as a type synonym; then we can throw away/repurpose the Foo data constructor. (I'm guessing your real example isn't so dumb.)

leaving around the old Foo alongside the new Bar, and clients will hopefully discover Bar when looking for more flexibility.

You mean the 'old' Foo type or constructor?

pattern synonyms, I was wondering if I could turn Foo into zero cost syntactic sugar for creating a Bar.

The underneath line/where in the pattern decl does that, just copying the code in the q.

As the commenters have noted, you can't declare a pattsyn to be build-only: their chief intended usage is for pattern matching. So [] the top/ ...) construct is a ViewPattern, and they're almost always needed when declaring real-life pattsyns. Since the q says it's impossible to recover the original Foo from the new-fangled Bar, I've hard-coded four Strings. The (const (blah) -> ...) in effect says to ignore the (Bar ...) value.

Caveat: There's nothing in pattsyn Foo's decl that can prevent client code pattern matching on it. (For all anybody knows it's already doing that.) Then it'll get a nonsense result. I suggest a tuple of undefineds rather than hard-coded Strings.

March 9, 2026 Score: 2 Rep: 156,300 Quality: Low Completeness: 50%

Probably the best you can do with existing technology is to simply convert the pattern match to a runtime error -- rather than a compile-time error. Like this:

data Bar = Bar (Bool -> Int -> Bool -> String)
pattern Foo :: HasCallStack => String -> Bar
pattern Foo s  s)
    where Foo s = Bar (\  _ -> s)

Try it in ghci:

> let Foo x = Bar mempty in length x
* Exception: Foo is for construction only
CallStack (from HasCallStack):
  error, called at test.hs:9:19 in main:Main
  Foo, called at :1:5 in interactive:Ghci1
> let Bar f = Foo "x" in f True 3 False
"x"

You might also want type Foo = Bar in case your existing callers mentioned Foo in a type signature.