我正在通过直接跳到OpenGL来学习Haskell,但似乎无法破译此代码:display :: DisplayCallbackdisplay = 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到目前为止,我的理解是:display是一个函数。问题:什么是DisplayCallback?do表示计算链,与IO monad有关color3f和vertex3f是局部函数,使用do关键字在let中定义了三个参数我假设color和vertex是glColor*和glVertex*的openGL包装函数。现在这是令人困惑的地方:Color3和Vertex3似乎是由三个参数组成的某种数据结构。问题:为什么这里需要使用数据结构?为什么API的设计者选择在这里使用它?color3f函数调用color函数,并传入单个参数-具有数据r g b的数据结构Color3。由于某种原因,此处仅为最后一个参数指定了数据类型(b :: GLfloat)问题:为什么仅为最后一个参数指定了数据类型,为什么在这里完全指定了它?问题:为什么在调用color函数color $ Color3 r g (b :: GLfloat)时使用美元符号?继续:clear是opengl glClear的包装,并以一个列表作为参数,在这种情况下,该列表仅包含单个元素[ColorBuffer]。renderPrimitive似乎是opengl glBegin的包装函数,Quads似乎是数据类型。问题:接下来会发生什么? $ do表示什么? (一系列计算?某些东西,一些IO monad?)。flush是glFlush的包装。 最佳答案 1。 DisplayCallback是IO ()的类型同义词。您可以使用hoogle来查找内容,也可以在ghci中键入:i DisplayCallback。IO ()被赋予特殊名称的原因是GLUT基于回调:注册了用于处理特定事件(例如显示,输入事件,调整大小事件等)的函数。有关完整列表,请参见。显然,您不需要类型同义词,但是提供它们是为了清楚和更好地进行通信。2。 “我假设颜色和顶点是glColor *和glVertex *的openGL包装函数。”不太完全-OpenGL是更基本的OpenGLRaw的包装,这是c opengl库与haskell的1:1映射。 vertex和color比glColor和glVertex稍微复杂一些,但是您可以假定在大多数情况下它们是相同的。更具体地说,vertex是Vertex类的成员,该类具有4个实例Vertex4,Vertex3和Vertex2。3。 Color3被定义为data Color3 a = Color3 !a !a !a。 docs。为什么这是必要的?好了,他们本来可以很容易地使用(a,a,a) -> IO ()或a -> a -> a -> IO (),但是带颜色的功能与带矢量的颜色是无法区分的,即使它们由完全相同的数据表示(“顶点是data Vertex3 a = Vertex3 !a !a !a)。因此,您不希望能够将顶点传递给需要颜色的函数。同样,由于严格性,这些数据类型也可以提供更好的性能。4。为什么要指定类型?简短的答案是类型系统需要它。文字的类型是Num a => a,对于数据类型而言,该变量过于多态,因此需要具体的类型。因此,您可以使用类型注释选择具体的类型。为什么只在一个地方需要它?编译器可以推断其他字段的类型。回顾数据类型定义-所有三个字段必须具有相同的类型。如果注释了一个字段,则可以轻松推断其余字段。您也可以编写Color3 r (g :: GLfloat) b或Color3 (r :: GLfloat) g b或为函数vertex3f提供类型签名。5。 $只是具有较低优先级的函数应用程序,它定义为f $ a = f a; infixr $ 0。您也可以编写color (Color3 r g (b :: GLfloat)),所以这里纯粹是样式问题。6。 The exclamation indicates that the fields are strict.但简短的版本是这样:您不是在renderPrimitive-glBegin块中编写内容,而是在glEnd中编写了它。您不需要编写renderPrimitive,因为它隐藏在glEnd内部。因此,您的代码等效于:glBegin (GL_QUADS);// All the stuff inside goes here ...glEnd ();renderPrimitive进行了一些魔术操作,以将c中的异常正确地引入到haskell宇宙中,但是您不必为此担心。最后的评论:如果您打算将haskell用于图形,编写实际的openGL代码可能不是最好的主意。毕竟,如果要使用openGL,为什么不只使用c?那里有各种各样的图形库。您应该浏览hackage以找到适合您的软件包。恐怕我什么都不推荐,因为我对可用的软件包不熟悉。 10-08 07:53