我正在尝试实现类似于HaTeX中编程的功能,程序员将逐行编写LaTeX命令作为文本。他们的示例之一如下:
class AddableFunction:
'''
Function decorator that lets (f+g)(x) = f(x) + g(x).
'''
def __init__(self, function):
self._function = function
def __call__(self, *args, **kwargs):
return self._function(*args, **kwargs)
def __add__(self, other):
return AddableFunction(lambda *args, **kwargs: self(*args, **kwargs) + other(*args, **kwargs))
@AddableFunction
def f(x):
return x ** 2
@AddableFunction
def g(x):
return x ** 3
print((f + g)(1)) # 2
print((f + g)(2)) # 12
print((f + g)(3)) # 36
完整示例: https://github.com/Daniel-Diaz/HaTeX/blob/master/Examples/simple.hs
到目前为止,我已经实现了以下目标:
-- Body with a section.
theBody :: Monad m => LaTeXT_ m
theBody = do
maketitle
section "Hello"
"This is a simple example using the "
hatex
" library. "
-- 'textbf' turns characters to bold font (as you already may know).
textbf "Enjoy!"
" "
但是我真的很想摆脱module Main
where import System.IO
writeContent :: String
writeContent = do
"Some text. "
++ "Some more text. "
++ "This should all compile into a single line "
++ "and be output to the screen."
main :: IO ()
main = do
putStr $ writeContent
运算符。
我知道++
和Strings
的效率不及++
,因此一旦我学到更多,最终将改变这一状况。对Haskell来说还很陌生。我尝试浏览过HaTeX的源代码,但是在某些部分中,一行中完成了太多步骤,因此想一次构建这些小步骤。
答案 0 :(得分:2)
您可以使用writer monad:
import Control.Monad.Trans.Writer
writeContent :: Writer String ()
writeContent = do
tell "Some text. "
tell "Some more text. "
tell "This should all compile into a single line "
tell "and be output to the screen."
main :: IO ()
main = do
putStr $ execWriter writeContent
要执行此操作而没有像tell
这样的额外(可见)函数调用,您需要OverloadedStrings
extension:
{-# LANGUAGE GADTs, GeneralizedNewtypeDeriving, OverloadedStrings
#-}
import Control.Monad.Trans.Writer
import Data.String
newtype StringBuilder a =
StringBuilder (Writer String a)
deriving (Functor, Applicative, Monad)
instance (a ~ ()) => IsString (StringBuilder a) where
fromString = StringBuilder . tell
buildString :: StringBuilder () -> String
buildString (StringBuilder w) = execWriter w
writeContent :: StringBuilder ()
writeContent = do
"Some text. "
"Some more text. "
"This should all compile into a single line "
"and be output to the screen."
main :: IO ()
main = do
putStr $ buildString writeContent