Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这个OpenGL Haskell代码是如何工作的?_Opengl_Haskell_Monads - Fatal编程技术网

这个OpenGL Haskell代码是如何工作的?

这个OpenGL Haskell代码是如何工作的?,opengl,haskell,monads,Opengl,Haskell,Monads,我通过直接跳入OpenGL来学习Haskell,但我似乎无法破解以下代码: display :: DisplayCallback display = do let color3f r g b = color $ Color3 r g (b :: GLfloat) vertex3f x y z = vertex $ Vertex3 x y (z :: GLfloat) clear [ColorBuffer] renderPrimitive Quads $ do c

我通过直接跳入OpenGL来学习Haskell,但我似乎无法破解以下代码:

display :: DisplayCallback
display = do
  let color3f r g b = color $ Color3 r g (b :: GLfloat)
      vertex3f x y z = vertex $ Vertex3 x y (z :: GLfloat)

  clear [ColorBuffer]
  renderPrimitive Quads $ do
    color3f 1 0 0
    vertex3f 0 0 0
    vertex3f 0 0.2 0
    vertex3f 0.2 0.2 0
    vertex3f 0.2 0 0

    color3f 0 1 0
    vertex3f 0 0 0
    vertex3f 0 (-0.2) 0
    vertex3f 0.2 (-0.2) 0
    vertex3f 0.2 0 0

    color3f 0 0 1
    vertex3f 0 0 0
    vertex3f 0 (-0.2) 0
    vertex3f (-0.2) (-0.2) 0
    vertex3f (-0.2) 0 0

    color3f 1 0 1
    vertex3f 0 0 0
    vertex3f 0 0.2 0
    vertex3f (-0.2) 0.2 0
    vertex3f (-0.2) 0 0
  flush
到目前为止,我的理解是:

  • 显示
    是一项功能问题:什么是DisplayCallback
  • do
    表示计算链,与IO单子有关
  • color3f
    vertex3f
    是本地函数,使用
    let
    关键字在
    do
    中定义了三个参数
  • 我假设
    color
    vertex
    glColor*
    glVertex*
    的openGL包装函数 现在这是让人困惑的地方:

    • Color3
      Vertex3
      似乎是由三个参数组成的某种数据结构问题:为什么需要在此处使用数据结构?为什么API的设计者选择在这里使用它

    • color3f
      函数调用
      color
      函数,并使用数据rgb传入单参数-数据结构
      Color3
      。出于某种原因,此处仅为最后一个参数指定了数据类型
      (b::GLfloat)
      问题:为什么只为最后一个参数指定了数据类型,为什么在此处指定

    • 问题:调用
      color
      函数
      color$Color3 r g(b::GLfloat)
      时为什么使用美元符号

    继续:

  • clear
    是opengl
    glClear
    的包装器,并将列表作为参数,在本例中,列表仅包含单个元素
    [ColorBuffer]
  • renderPrimitive
    似乎是opengl的包装函数
    glBegin
    Quads
    似乎是数据类型问题:接下来会发生什么?
    $do
    表示什么?(一系列的计算?什么,什么?)
  • flush
    glFlush
    的包装器

  • 我不知道有问题的实际图书馆,但我想我可以回答你的一些观点

    我想,
    DisplayCallback
    只是一些更复杂类型签名的别名。如果打开GHCi并导入必要的模块,您应该能够说

    :i DisplayCallback
    
    它会告诉你它指的是什么。然后至少你会看到定义,即使它不一定告诉你它的用途

    do
    符号不仅适用于IO单子,也适用于任何单子。如果OpenGL绘图操作发生在他们自己的专业monad中,我不会感到惊讶

    为什么指定了
    GLFloat
    ?我想象
    Color3
    Vector3
    被定义为保存任何类型的坐标。我们希望它是
    GLFloat
    ,因此是类型签名。为什么它只在一个坐标上?我可以想象,
    Color3
    的定义要求所有坐标都具有相同的类型,因此为一个坐标指定它会自动导致其他两个坐标具有相同的类型

    为什么
    Color3
    甚至存在?为什么我们不能用三个输入调用
    color
    ?好吧,这是一个API设计选择,但如果
    Color3
    Vector3
    的定义允许您对整个向量或颜色进行算术运算,我也不会感到惊讶。因此,通过将坐标放入一个向量,你可以将它们视为一个单独的单元,对它们进行算术运算,轻松地将它们存储在列表中,等等。如果你正在做这些,你就不需要为了调用OpenGL函数而再次将它们全部解包

    美元符号是什么意思?好吧,如果我写信

    color Color3 r g b
    
    这意味着我正在调用
    color
    ,向它传递四个参数:
    Color3
    r
    g
    b
    。这不是我们想要的。我们想要的是

    color (Color3 r g b)
    
    也就是说,使用一个参数调用
    color
    。您可以使用括号,也可以使用
    $
    。它有点像Unix管道,因为它允许您

    func3 (func2 (func1 x))
    
    进入

    如果您有很多函数,那么获取正确数量的右括号可能会很烦人。对于一个函数调用,这是一个品味的问题

    renderPrimitive
    函数有两个参数。其中一个是
    Quads
    (不管是什么),另一个是整个do块。因此,您将所有代码作为参数传递给
    renderPrimitive
    函数(该函数可能以某种方式执行它)


    希望这能给你一些启示。

    1
    DisplayCallback
    IO()
    的类型同义词。您可以使用hoogle查找内容,或者在ghci中键入
    :i DisplayCallback

    之所以给
    IO()
    一个特殊名称,是因为
    GLUT
    基于回调:注册函数以处理特定事件,例如显示、输入事件、调整事件大小等。有关完整列表,请参阅。显然,您不需要类型同义词,但它们是为了清晰和更好的交流而提供的

    二,。“我假设color and vertex是glColor*和glVertex*的openGL包装函数”不完全-
    openGL
    是更基本的
    OpenGLRaw
    的包装,它是c openGL库到haskell的1:1映射
    vertex
    color
    glColor
    glVertex
    稍微复杂一些,但您可能会假设在大多数情况下它们是相同的

    更具体地说,
    vertex
    vertex
    类的成员,该类有4个实例
    Vertex4
    Vertex3
    Vertex2

    三,
    Color3
    定义为
    data Color3 a=Color3!A.A.a
    。为什么这是必要的?嗯,他们可以很容易地使用
    (a,a,a)->IO()func3 $ func2 $ func1 $ x
    
    glBegin (GL_QUADS); 
    // All the stuff inside goes here ...
    glEnd ();