将函数表示为类型
Representing Functions as Types
一个函数可以是一个高度嵌套的结构:
function a(x) {
return b(c(x), d(e(f(x), g())))
}
首先,想知道一个函数是否有一个实例。也就是说,函数的评估是函数的实例。从这个意义上说,类型就是函数,实例就是对函数的求值。如果可以,那么如何将函数建模为类型(在某些面向类型理论的语言中,如 Haskell 或 Coq)。
几乎就像:
type a {
field: x
constructor b {
constructor c {
parameter: x
},
...
}
}
但我不确定我是否走在正确的轨道上。我知道您可以说函数具有 [return] 类型。但是我想知道一个函数是否可以被认为是一种类型,如果是这样,如何在面向类型理论的语言中将其建模为一种类型,它在其中对函数的实际实现进行建模。
我不太清楚你的目标是什么,所以我会尝试指出一些你可能想要阅读的相关术语。
函数不仅有 return 类型,还有描述其参数的类型。所以 f
的 (Haskell) 类型读取 "f takes an Int and a Float, and returns a List of Floats."
f :: Int -> Float -> [Float]
f i x = replicate i x
类型还可以描述更多的函数规范。在这里,我们可能希望类型说明列表的长度与第一个参数相同,或者列表的每个元素都与第二个参数相同。长度索引列表(通常称为向量)是依赖类型的第一个常见示例。
您可能还对将类型作为参数的函数和 return 类型感兴趣。这些有时称为 "type-level functions"。在 Coq 或 Idris 中,它们的定义方式与更熟悉的函数相同。在Haskell中,我们通常使用Type Families, or using Type Classes with Functional Dependencies.
来实现它们
回到问题的第一部分,Beta Reduction 是为函数的每个参数填充具体值的过程。我听说有人将表达式描述为 "after reduction" 或 "fully reduced" 以强调此过程中的某个阶段。这类似于函数 Call Site,但强调表达式和参数,而不是周围的上下文。
我认为问题是直接基于实现的类型(我们称之为 "i-types")似乎不是很有用,我们已经有了很好的建模方法(称为 "programs" -- 哈哈).
在您的具体示例中,您函数的完整 i 类型,即:
type a {
field: x
constructor b {
constructor c {
parameter: x
},
constructor d {
constructor e {
constructor f {
parameter: x
}
constructor g {
}
}
}
}
只是实现本身的一种冗长的替代语法。也就是说,我们可以将此 i-type(以 Haskell 类语法)写为:
itype a :: a x = b (c x) (d (e (f x) g))
另一方面,我们可以将您的函数 implementation 直接转换为 Haskell 术语级语法,将其写为:
a x = b (c x) (d (e (f x) g))
i-type 和实现完全一样。
您将如何使用这些 i 类型?编译器可能会通过派生参数和 return 类型来使用它们来对程序进行类型检查。 (幸运的是,有一些众所周知的算法,例如 Algorithm W,用于从此类 i-types 中同时导出和类型检查参数和 return 类型。)程序员可能不会使用 i-types直接——它们太复杂了,无法用于重构或推理程序行为。他们可能想查看编译器为参数和 return 类型派生的类型。
特别是,"modelling" Haskell 中类型级别的这些 i 类型似乎效率不高。 Haskell 已经可以在术语级别对它们进行建模。只需将您的 i-types 编写为 Haskell 程序:
a x = b (c x) (d (e (f x) g))
b s t = sqrt $ fromIntegral $ length (s ++ t)
c = show
d = reverse
e c ds = show (sum ds + fromIntegral (ord c))
f n = if even n then 'E' else 'O'
g = [1.5..5.5]
不要运行。恭喜,您已成功为这些 i 类型建模!您甚至可以使用 GHCi 查询派生参数和 return 类型:
> :t a
a :: Floating a => Integer -> a -- "a" takes an Integer and returns a float
>
现在,您可能会想象在某些情况下实现和 i-type 会出现分歧,也许是在您开始引入文字值时。例如,也许你觉得上面的函数f
:
f n = if even n then 'E' else 'O'
应该分配一个类似于下面的类型,它不依赖于特定的文字值:
type f {
field: n
if_then_else {
constructor even { -- predicate
parameter: n
}
literal Char -- then-branch
literal Char -- else-branch
}
同样,您最好定义一个任意的术语级别 Char
,例如:
someChar :: Char
someChar = undefined
并在术语级别对此 i 类型建模:
f n = if even n then someChar else someChar
再说一次,只要你没有运行这个程序,你已经成功建模了f
的i类型,可以查询它的参数和return类型,将其作为更大程序的一部分进行类型检查等。
一个函数可以是一个高度嵌套的结构:
function a(x) {
return b(c(x), d(e(f(x), g())))
}
首先,想知道一个函数是否有一个实例。也就是说,函数的评估是函数的实例。从这个意义上说,类型就是函数,实例就是对函数的求值。如果可以,那么如何将函数建模为类型(在某些面向类型理论的语言中,如 Haskell 或 Coq)。
几乎就像:
type a {
field: x
constructor b {
constructor c {
parameter: x
},
...
}
}
但我不确定我是否走在正确的轨道上。我知道您可以说函数具有 [return] 类型。但是我想知道一个函数是否可以被认为是一种类型,如果是这样,如何在面向类型理论的语言中将其建模为一种类型,它在其中对函数的实际实现进行建模。
我不太清楚你的目标是什么,所以我会尝试指出一些你可能想要阅读的相关术语。
函数不仅有 return 类型,还有描述其参数的类型。所以 f
的 (Haskell) 类型读取 "f takes an Int and a Float, and returns a List of Floats."
f :: Int -> Float -> [Float]
f i x = replicate i x
类型还可以描述更多的函数规范。在这里,我们可能希望类型说明列表的长度与第一个参数相同,或者列表的每个元素都与第二个参数相同。长度索引列表(通常称为向量)是依赖类型的第一个常见示例。
您可能还对将类型作为参数的函数和 return 类型感兴趣。这些有时称为 "type-level functions"。在 Coq 或 Idris 中,它们的定义方式与更熟悉的函数相同。在Haskell中,我们通常使用Type Families, or using Type Classes with Functional Dependencies.
来实现它们回到问题的第一部分,Beta Reduction 是为函数的每个参数填充具体值的过程。我听说有人将表达式描述为 "after reduction" 或 "fully reduced" 以强调此过程中的某个阶段。这类似于函数 Call Site,但强调表达式和参数,而不是周围的上下文。
我认为问题是直接基于实现的类型(我们称之为 "i-types")似乎不是很有用,我们已经有了很好的建模方法(称为 "programs" -- 哈哈).
在您的具体示例中,您函数的完整 i 类型,即:
type a {
field: x
constructor b {
constructor c {
parameter: x
},
constructor d {
constructor e {
constructor f {
parameter: x
}
constructor g {
}
}
}
}
只是实现本身的一种冗长的替代语法。也就是说,我们可以将此 i-type(以 Haskell 类语法)写为:
itype a :: a x = b (c x) (d (e (f x) g))
另一方面,我们可以将您的函数 implementation 直接转换为 Haskell 术语级语法,将其写为:
a x = b (c x) (d (e (f x) g))
i-type 和实现完全一样。
您将如何使用这些 i 类型?编译器可能会通过派生参数和 return 类型来使用它们来对程序进行类型检查。 (幸运的是,有一些众所周知的算法,例如 Algorithm W,用于从此类 i-types 中同时导出和类型检查参数和 return 类型。)程序员可能不会使用 i-types直接——它们太复杂了,无法用于重构或推理程序行为。他们可能想查看编译器为参数和 return 类型派生的类型。
特别是,"modelling" Haskell 中类型级别的这些 i 类型似乎效率不高。 Haskell 已经可以在术语级别对它们进行建模。只需将您的 i-types 编写为 Haskell 程序:
a x = b (c x) (d (e (f x) g))
b s t = sqrt $ fromIntegral $ length (s ++ t)
c = show
d = reverse
e c ds = show (sum ds + fromIntegral (ord c))
f n = if even n then 'E' else 'O'
g = [1.5..5.5]
不要运行。恭喜,您已成功为这些 i 类型建模!您甚至可以使用 GHCi 查询派生参数和 return 类型:
> :t a
a :: Floating a => Integer -> a -- "a" takes an Integer and returns a float
>
现在,您可能会想象在某些情况下实现和 i-type 会出现分歧,也许是在您开始引入文字值时。例如,也许你觉得上面的函数f
:
f n = if even n then 'E' else 'O'
应该分配一个类似于下面的类型,它不依赖于特定的文字值:
type f {
field: n
if_then_else {
constructor even { -- predicate
parameter: n
}
literal Char -- then-branch
literal Char -- else-branch
}
同样,您最好定义一个任意的术语级别 Char
,例如:
someChar :: Char
someChar = undefined
并在术语级别对此 i 类型建模:
f n = if even n then someChar else someChar
再说一次,只要你没有运行这个程序,你已经成功建模了f
的i类型,可以查询它的参数和return类型,将其作为更大程序的一部分进行类型检查等。