- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试构建一个抽象语法树,该树允许使用monad do
表示法进行定义,如下所示:
ast = do
Variable uint8 "i"
Function Void "f" $ do
Variable uint8 "local_y"
Comment "etc. etc."
{-# LANGUAGE ExistentialQuantification #-}
module Question
where
import Control.Applicative
import Data.Monoid (Monoid, (<>))
import Data.String.Utils (rstrip)
type NumberOfBits = Word
type VariableName = String
data Type = UInt NumberOfBits
| Int NumberOfBits
| Void
uint8 = UInt 8
int8 = Int 8
instance Show Type where
show (UInt w) = "uint" <> show w
show (Int w) = "int" <> show w
show Void = "void"
data TreeM a = Variable Type VariableName -- variable declaration
| Function Type VariableName (TreeM a) -- function declaration
| Comment String -- a comment
| PlaceHolder String -- a placeholder with
| forall b. Append (TreeM b) (TreeM a) -- combiner
| Empty a -- needed for what?
type Tree = TreeM ()
subTreeOf :: TreeM a -> a
subTreeOf (Variable _ _) = undefined
subTreeOf (Function _ _ t) = subTreeOf t
subTreeOf (Comment _) = undefined
subTreeOf (Empty t) = t
instance Monoid a => Monoid (TreeM a) where
mempty = Empty mempty
mappend = Append
mconcat = foldr Append mempty
instance Functor TreeM where
fmap f x = x `Append` (Empty (f (subTreeOf x))) -- fmap :: (a -> b) -> f a -> f b
instance Applicative TreeM where
pure x = Empty x
(<*>) x y = (x `Append` y) `Append` (Empty (subTreeOf x (subTreeOf y))) -- (<*>) :: f (a -> b) -> f a -> f b
(*>) = Append
instance Monad TreeM where
return x = Empty x
(>>) = Append -- not really needed: (>>) would default to (*>)
t >>= f = t `Append` (f (subTreeOf t))
indent :: String -> String
indent s = rstrip $ unlines $ map (" "<>) (lines s)
render :: TreeM a -> String
render (Variable y n) = "Variable " <> (show y) <> " " <> show n
render (Function r n t) = "Function" <> " " <> n <> " returning " <> (show r) <> ":\n" <> indent (render t)
render (PlaceHolder n) = "Placeholder \"" <> n <> "\""
render (Append t t') = (render t) <> "\n" <> (render t')
render (Empty _) = ""
-- |In input tree t substitute a PlaceHolder of name n' with the Tree t'
sub :: TreeM a -> (String, TreeM a) -> TreeM a
sub t@(PlaceHolder n) (n', t') = if n == n' then t' else t
sub (Function y n t) s = Function y n (sub t s)
--sub (Append t t') s = Append (sub t s) (sub t' s) -- Error!
sub t _ = t
code :: Tree
code = do
Variable uint8 "i"
Variable int8 "j"
Function Void "f" $ do
Comment "my function f"
Variable int8 "i1"
Variable int8 "i2"
PlaceHolder "the_rest"
main :: IO ()
main = do
putStrLn $ render code
putStrLn "\nNow apply substitution:\n"
putStrLn $ render (sub code ("the_rest", Comment "There is nothing here"))
a
中
TreeM a
的确切含义。我看
a
的方式可以是
Variable
,
Function
,
PlaceHolder
等任何类型。
forall b. Append (TreeM b) (TreeM a)
中,
TreeM a
和
TreeM b
自变量的顺序似乎相反。无论如何,总和类型中存在量词的使用看起来很奇怪。如果我正确理解这一点,它将为
Append
定义一系列构造函数。
TreeM
,
Functor
和
Applicative
所需的所有功能中,唯一实际使用的是monad
Monad
。 (这表明一个免费的monad可能是完成此工作的正确工具。)实际上,我从来没有想到do表示法使用了
>>
运算符并且可以使用此事实。
>>
中使用
undefined
。
subTreeOf
的定义对于HTML树很有意义,它用于
Empty
这样的空标记。但是对于AST,这没有任何意义。保持
<br />
和
Applicative
实现正常工作。
Functor
和
Functor
的实现可能对HTML树有意义,但对AST没有意义。即使对于HTML,我也不太了解
Applicative
和适用性
fmap
的目的。两者都通过按下节点并添加
<*>
类型来扩展树。我不太明白HTML树上代表了哪种自然转换。
Empty
定义中的
subTreeOf x (subTreeOf y)
实际上是正确的语法,还是存在隐式的
<*>
?
>>
用作应用转换的小玩具。这里只有部分实现的函数
PlaceHolder
应该用注释替换占位符“ the_rest”。必要
sub
无法编译,但是
sub (Append t t') s = Append (sub t s) (sub t' s)
的预期类型是
s
,实际类型是
(String, TreeM b)
。
(String, TreeM a)
破坏了
sub :: TreeM a -> (String, TreeM b) -> TreeM a
的定义,现在我陷入了困境。
sub p@(PlaceHolder n)
到底应该是什么?
sub
fmap
进行免费的构造,此处显示的
Functor
不足以用于AST。一旦识别出正确的
fmap
,则免费的monad应该执行其余的操作-也许可以。
fmap
fmap
是成功的关键,而正确的
fmap
可能会变得更加明显。
fmap
编写循环,这是构建AST重复部分的一种好方法:
forM_ ["you", "get", "the", "idea"] $ \varName -> do
Variable uint8 varName
<*>
,
forM_
等。
when hasCppDestructor $ do
Comment "We need the destructor"
Function NoReturnType "~SomeClass" $ do
...
when
等)以小写开头,而AST行以大写开头。
unless
函数然后将可以证明正确的AST映射到目标语言。
forM_
并非默认为
render
,而是默认为
>>
!
最佳答案
我不确定整个方法是否是一个好主意(尽管我实际上已经做过很多次类似的事情了)。
请注意,诸如Blaze.MarkupM
,HaTeX.LaTeXM
等的单子并不是真正的单子。它们实际上只是想要访问Monadic组合器的类对象(主要是滥用do
表示法,但它也允许在顶部使用堆栈monad转换器,这在一定程度上是有道理的)。也就是说,它们不过是专门的Writer
单子。如果您打算这样做,那么最好的方法是将类型设计为Monoid Tree
,然后查看Writer Tree
monad的结构,如果需要,将其重构为< cc>数据结构。 (HaTeX不会这样做,但是将TreeM
和LaTeX
的类型保留为单独的类型,而只有一个通用的类接口,这可以说是一种更简洁的方法,尽管它可能不是最佳的性能。)
结果将非常类似于LaTeXM
/您现在拥有的结构。我可以讨论您的个人问题,但实际上,只需查看类型对作者单子的同构性就可以回答所有问题。
实际上,使用Blaze.MarkupM
完全不需要Monad
实例,例如:
Prelude> 2 * do 1 + 1
4
do
以避免树形布局中出现括号,而实际上并没有在结构中存储可绑定变量的明智方法,请考虑不要编写任何monad实例。只有多行的
do
块才需要该实例,但是如果这些行都没有绑定任何变量,那么您始终可以将隐式的
do
替换为显式的
>>
,例如
Function Void "f" $ do
Variable uint8 "local_y"
<> Comment "etc. etc."
<>
运算符,因为它的优先级低于
$
。避免这种情况的一种不错的方法是观察
<>
,因此您可以将示例编写为
ast = do
Variable uint8 "i"
<> Function Void "f" `id`do
Variable uint8 "local_y"
<> Comment "etc. etc."
($) = id
一样,因为它还提供了允许在AST构建中包括
HaTeX
操作的选项(例如,硬包含)外部源文件)。
IO
实例不仅有意义,它实际上是一种有用的方法,它可以绑定变量。这是一项不适用于
Monad
的功能,但肯定适用于AST等C ++ / Python / JavaScript语言,并且它非常有用,因为它可以确保在使用之前在Haskell语法内定义变量。而不是您的示例,您将编写
ast = do
i <- variable uint8
Function Void "f" $ do
local_y <- variable uint8
Comment "etc. etc."
type VariableName = Int
data TreeS = Variable Type VariableName
| Function Type VariableName TreeS
| Comment String
| PlaceHolder String
| Append TreeS TreeS
| Empty
instance Monoid where (<>) = Append
newtype TreeT m a
= TreeT { runTreeM :: StateT VariableName (WriterT TreeS m) a }
deriving (Functor, Applicative, Monad)
variable :: Type -> TreeT m VariableName
variable typ = TreeT $ do
i <- get
lift . tell $ Variable typ i
put $ i+1
return i
关于haskell - 使用Haskell monad“do”表示法定义语法树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48136060/
在 Haskell 中,类型声明使用双冒号,即 (::),如 not::Bool -> Bool。 但是在许多语法与 Haskell 类似的语言中,例如榆树、 Agda 、他们使用单个冒号(:)来声明
insertST :: StateDecoder -> SomeState -> Update SomeState SomeThing insertST stDecoder st = ... Stat
如果这个问题有点含糊,请提前道歉。这是一些周末白日梦的结果。 借助 Haskell 出色的类型系统,将数学(尤其是代数)结构表达为类型类是非常令人愉快的。我的意思是,看看 numeric-prelud
我有需要每 5 分钟执行一次的小程序。 目前,我有执行该任务的 shell 脚本,但我想通过 CLI 中的键为用户提供无需其他脚本即可运行它的能力。 实现这一目标的最佳方法是什么? 最佳答案 我想你会
RWH 面世已经有一段时间了(将近 3 年)。在在线跟踪这本书的渐进式写作之后,我渴望获得我的副本(我认为这是写书的最佳方式之一。)在所有相当学术性的论文中,作为一个 haskell 学生,读起来多么
一个经典的编程练习是用 Lisp/Scheme 编写一个 Lisp/Scheme 解释器。可以利用完整语言的力量来为该语言的子集生成解释器。 Haskell 有类似的练习吗?我想使用 Haskell
以下摘自' Learn You a Haskell ' 表示 f 在函数中用作“值的类型”。 这是什么意思?即“值的类型”是什么意思? Int 是“值的类型”,对吗?但是 Maybe 不是“值的类型”
现在我正在尝试创建一个基本函数,用于删除句子中的所有空格或逗号。 stringToIntList :: [Char] -> [Char] stringToIntList inpt = [ a | a
我是 Haskell 的新手,对模式匹配有疑问。这是代码的高度简化版本: data Value = MyBool Bool | MyInt Integer codeDuplicate1 :: Valu
如何解释这个表达式? :t (+) (+3) (*100) 自 和 具有相同的优先级并且是左结合的。我认为这与 ((+) (+3)) (*100) 相同.但是,我不知道它的作用。在 Learn
这怎么行 > (* 30) 4 120 但这不是 > * 30 40 error: parse error on input ‘*’ 最佳答案 (* 30) 是一个 section,它仍然将 * 视为
我想创建一个函数,删除满足第二个参数中给定谓词的第一个元素。像这样: removeFirst "abab" ( 'b') = "abab" removeFirst [1,2,3,4] even =
Context : def fib(n): if n aand returns a memoized version of the same function. The trick is t
我明白惰性求值是什么,它是如何工作的以及它有什么优势,但是你能解释一下 Haskell 中什么是严格求值吗?我似乎找不到太多关于它的信息,因为惰性评估是最著名的。 他们各自的优势是什么。什么时候真正使
digits :: Int -> [Int] digits n = reverse (x) where x | n digits 1234 = [3,1,2,4]
我在 F# 中有以下代码(来自一本书) open System.Collections.Generic type Table = abstract Item : 'T -> 'U with ge
我对 Haskell 比较陌生,过去几周一直在尝试学习它,但一直停留在过滤器和谓词上,我希望能得到帮助以帮助理解。 我遇到了一个问题,我有一个元组列表。每个元组包含一个 (songName, song
我是 haskell 的初学者,我试图为埃拉托色尼筛法定义一个简单的函数,但它说错误: • Couldn't match expected type ‘Bool -> Bool’
我是 Haskell 语言的新手,我在使用 read 函数时遇到了一些问题。准确地说,我的理解是: read "8.2" + 3.8 应该返回 12.0,因为我们希望返回与第二个成员相同的类型。我真正
当我尝试使用真实项目来驱动它来学习 Haskell 时,我遇到了以下定义。我不明白每个参数前面的感叹号是什么意思,我的书上好像也没有提到。 data MidiMessage = MidiMessage
我是一名优秀的程序员,十分优秀!