3

While I was browsing Persistent source code, I came across this function below in file Quasi.hs (I referred to a tag with the relevant code equal to the one in the present state in master branch, since the tag's code is more unlikely to change). In the line takeConstraint ps tableName defs (n:rest) | not (T.null n) && isUpper (T.head n) = takeConstraint' there is this pipe (|) character following the argument pattern. Is the expression between | and = like a constraint to arguments in the pattern? So do I interpret this | as the same symbol in Math, i.e. "such that"?

takeConstraint :: PersistSettings
          -> Text
          -> [FieldDef]
          -> [Text]
          -> (Maybe FieldDef, Maybe CompositeDef, Maybe UniqueDef, Maybe UnboundForeignDef)
takeConstraint ps tableName defs (n:rest) | not (T.null n) && isUpper (T.head n) = takeConstraint' --- <<<<< This line
    where
      takeConstraint' 
            | n == "Unique"  = (Nothing, Nothing, Just $ takeUniq ps tableName defs rest, Nothing)
            | n == "Foreign" = (Nothing, Nothing, Nothing, Just $ takeForeign ps tableName defs rest)
            | n == "Primary" = (Nothing, Just $ takeComposite defs rest, Nothing, Nothing)
            | n == "Id"      = (Just $ takeId ps tableName (n:rest), Nothing, Nothing, Nothing)
            | otherwise      = (Nothing, Nothing, Just $ takeUniq ps "" defs (n:rest), Nothing) -- retain compatibility with original unique constraint
takeConstraint _ _ _ _ = (Nothing, Nothing, Nothing, Nothing)

1 Answer 1

6

Yes, it means precisely “such that”. These are guards, very common in Haskell (generally preferred to the equivalent if then else expression).

f x
 | x > 2      = a
 | x < -4     = b
 | otherwise  = x

is equivalent to

f x = if x > 2 then a
               else if x < -4 then b
                              else x

IMO that specific example would actually have better been written with neither if nor guards, but

    takeConstraint' = case n of
        "Unique"  -> (Nothing, Nothing, Just $ takeUniq ps tableName defs rest, Nothing)
        "Foreign" -> (Nothing, Nothing, Nothing, Just $ takeForeign ps tableName defs rest)
        "Primary" -> (Nothing, Just $ takeComposite defs rest, Nothing, Nothing)
        "Id"      -> (Just $ takeId ps tableName (n:rest), Nothing, Nothing, Nothing)
        _         -> (Nothing, Nothing, Just $ takeUniq ps "" defs (n:rest), Nothing)
Sign up to request clarification or add additional context in comments.

2 Comments

The case looks better for me as well.
I agree, cramming a whole function block between after the guard was a bit misleading, I thought it was a completely novel feature from Haskell.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.