Home > Net >  Haskell error: `Qualified name in binding position`
Haskell error: `Qualified name in binding position`

Time:11-12

Here is the code:

import qualified View.TreeWidget as TreeWidget

main :: IO ()
main = do
  print $ bla "sdfsd"

bla someString = case someString of
  TreeWidget.name -> True
  "sdfsd" -> False
  _ -> True

TreeWidget.name is a function defined in a file TreeWidget.hs like this:

name :: String
name = "tree_list_name"

Here is the error:

src/View/Main.hs:8:3: error:
    Qualified name in binding position: TreeWidget.name
  |
8 |   TreeWidget.name -> True
  |   ^^^^^^^^^^^^^^^
  1. Why is this happening?
  2. What can be done?

Thanks.

CodePudding user response:

When you see a lower case pattern, that means a variable which matches everything. You might as well use a pattern wildcard (_) if the variable is not used on the right-hand side.

  name -> True

A pattern variable functions as a binder, you cannot substitute a pattern like "tree_list_name" -> .. with

  name -> ..

name :: String
name = "tree_list_name"

It also means you can't reference a pattern variable from some other module, which is what TreeWidget.name is doing.

The solution is to use pattern synonyms. In the View.TreeWidget module write something like

{-# Language PatternSynonyms #-}

module View.TreeWidget (pattern Name) where

pattern Name :: String
pattern Name = "tree_list_name"

Now you can use Name both as an expression and a pattern. So you can now write

import qualified View.TreeWidget as TreeWidget

bla :: String -> Bool
bla TreeWidget.Name = True
bla "sdfsd"         = False
bla _               = True

CodePudding user response:

As Iceland_jack explained, you can't use values like name as patterns. What you can use as patterns is essentially constructors and literals, where constructors are normally the uppercase things appearing in a data declaration like Just and Nothing in the Maybe type. The PatternSynonyms extension allows defining custom constructors for already declared types.

However, although I generally favour patterns over equality check, this seems to be a case where it would make more sense to just check whether someString == TreeWidget.name and act accordingly. This can easily be done with guards:

bla someString
 | someString==TreeWidget.name  = True
bla "sdfsd" = False
bla _ = True

Of course, since the result is again a boolean you could also just use logical operators:

bla someString = someString==TreeWidget.name || someString/="sdfsd"

If you have a taste for point-freeness, this can also be written

bla = or . ([(==TreeWidget.name), (/="sdfsd")]<*>) . pure

... but more effective would be to just use a shorter name for someString.

  • Related