Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
383 views
in Technique[技术] by (71.8m points)

compiler errors - How to create an analogue of Latex providecommand in Haskell?

Suppose we are importing a module M where we expect a function f1. But it may not be there. However, we do not want a compilation error, but we want to do something like the following (pseudocode):

 import M

 f2 = if (defined f1) then f1 else ...

In other words, I would like to make an analogue of Latex providecommand in Haskell:

https://latexref.xyz/_005cprovidecommand.html


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is probably a bad idea. However, if you really want to do it, @WillemVanOnsem's suggestion will work.

You can create the following separate module to define a Template Haskell (TH) function provideCommand. Note that you have to do this in a separate module from where you want to use provideCommand because of a limitation known as the TH "stage restriction", where TH functions can't be used (technically, can't be "spliced") in the same module where they're defined.

module ProvideCommand where

import Language.Haskell.TH

provideCommand :: String -> Q [Dec] -> Q [Dec]
provideCommand nam defn = do
  mval <- lookupValueName nam
  case mval of
    Just _ -> return []
    Nothing -> defn

This function uses lookupValueName to look up a given name at compile time. If the name is not found, it outputs some provided declarations.

You'd use it like so in some other module. You need to turn on the TemplateHaskell extension to call (i.e., "splice") provideCommand.

{-# LANGUAGE TemplateHaskell #-}

import M
import ProvideCommand

provideCommand "double" [d| double x = x * 2 |]

main = print (double 15)

If the name double is not already defined (e.g., in module M), this will define it by outputting the declarations in the quasiquote [d| ... |]. You can include multiple declarations, include for things other than double, but obviously they won't be available unless the provideCommand is triggered:

provideCommand "double"
  [d| double :: Int -> Int
      double 0 = 0
      double n = addTwo (double (n-1))

      addTwo :: Int -> Int
      addTwo x = x + 2
  |]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...