我不能很好地找到以下方面的手册:
如果我想在Haskell中获得功能的定义,那么我正在使用class ProgramTemplate < ActiveRecord::Base
#belongs_to :patient
#belongs_to :program
belongs_to :account
#belongs_to :account_patient
has_many :exercises, dependent: :destroy
accepts_nested_attributes_for :exercises, allow_destroy: true
#has_many :program_sessions, dependent: :destroy
# accepts_nested_attributes_for :exercises, reject_if: lambda { |e| e[:published].blank? }, allow_destroy: true
validates :name, presence: true
validate :min_no_of_exercises
例如:
:t
我会得到:
:t sqrt
:t (+)
:t truncate
我只是不确定如何了解这里的语法,涉及sqrt :: Floating a => a -> a
(+) :: Num a => a -> a -> a
truncate :: (RealFrac a, Integral b) => a -> b
和=>
。
我知道->
与函数的定义有关,其余的与函数定义有关。这对于全面了解功能非常重要。
答案 0 :(得分:5)
我知道
::
是关于定义函数的
er,不。 ::
表示您要提供类型签名,这不一定与定义函数有关(尽管在实践中,您应为每个编写的函数,即使不编写,编译器也会推断出一个签名。)
sqrt :: Double -> Double -- } type signature
sqrt 0 = 0 -- ⎫
sqrt 1 = 1 -- ⎪
sqrt 2 = 1.4 -- should do -- ⎬ definition
sqrt 4 = 2 -- ⎪
sqrt _ = error "too hard" -- ⎭
现在-正如您所看到的,这些签名实际上有些不同,而不仅仅是Double -> Double
。具体来说,签名sqrt :: Floating a => a -> a
解析为
sqrt :: forall a .
(Floating a)
=> (a -> a)
这意味着,对于所有类型a
(包括但不限于Double
)(包括但不限于instance Floating
),这实际上都适用。也就是说,类型必须支持Floating
class的接口。对于这些类型中的每一种,签名都是“自身类型”,即
sqrt :: Double -> Double
sqrt :: Complex Double -> Complex Double
sqrt :: Float -> Float
sqrt :: ExactSymbolic -> ExactSymbolic
,但不是sqrt :: String -> String
,因为String
既不是Floating
的实例,也不是Bool -> Char
的实例,后者甚至都不匹配a -> a
模式。
对于其他示例,它是相似的:
(+) :: Num a => a -> a -> a
定义了可以用作例如Num
class中所有类型的Int -> Int -> Int
或Rational -> Rational -> Rational
。truncate :: (RealFrac a, Integral b) => a -> b
实际上可以在两种不同的类型之间进行转换,例如Double -> Int
或Rational -> Integer
。要求参数为RealFrac
class,结果为Integral
class。如何定义所有这些功能是另一回事–类型签名并不能告诉您(尽管对于特别的“基本”功能,实际上可能只有一种明智的实现方式)给定类型签名)。要查看函数的定义方式,您需要查看源代码。这通常是从Haddock文档中链接的,签名的右边是小Source
链接。对于(+)
上的Double
之类的内置函数,您将找不到任何定义,因为它们实际上只能解析为primop,即硬件处理器指令。
答案 1 :(得分:0)
作者编辑 尽管对于我的基础水平和OP基础水平而言,这种解释足够接近,但此答复简直是错误的,请参阅下面的评论。请考虑其他答案。
一个接受Integer
并返回Float
的函数将被编写为Integer -> Float
。
但是,您的功能可能更通用。例如,它可以处理任何类型并返回String。诸如a
之类的虚拟名称将用于输入类型。由于签名在a
上是可变的,因此对可变参数类型的依赖性将用=>
书写。因此,签名将为a => a -> String
。如果您曾经做过类型理论,那就是Π型。否则,将=>
看作是用来表示“类型函数”的箭头。在此,“类型的函数”采用类型a
,并返回类型a -> String
,这是常规函数类型。 (请注意,=>
的优先级比->
的低,否则就没有意义了。)
如果您依赖的类型不能为任何类型,但必须是具有某些属性的类型,则必须通过在类型之前给出类名称来指定其属性类。在您的问题中,一种行为像实值浮点数的类型为Floating
。
因此,Floating a => a -> a
是一个依赖函数类型,取决于a
,它必须是Floating
类。同样,(RealFrac a, Integral b) => a -> b
是双重依赖的函数类型,第一个依赖项必须是RealFrac
类,而第二个必须是Integral
类。
::
只是值(或在类型理论中为“见证”)与其类型之间的分隔符。 truncate :: (RealFrac a, Integral b) => a -> b
只是意味着truncate
是{双依赖)类型(RealFrac a, Integral b) => a -> b