Eli*_*der 21 lisp haskell programming-languages scala static-typing
我已经阅读过像Scala或Haskell这样的静态类型语言,无法创建或提供Lisp apply函数:
(apply #'+ (list 1 2 3)) => 6
Run Code Online (Sandbox Code Playgroud)
或者可能
(apply #'list '(list :foo 1 2 "bar")) => (:FOO 1 2 "bar")
(apply #'nth (list 1 '(1 2 3))) => 2
Run Code Online (Sandbox Code Playgroud)
这是真的吗?
Dan*_*ral 10
在静态类型语言中完全可能.整个java.lang.reflect事情就是这样做.当然,使用反射可以提供与Lisp一样多的类型安全性.另一方面,虽然我不知道是否有支持这种功能的静态类型语言,但在我看来它可以做到.
让我展示一下我如何将Scala扩展为支持它.首先,让我们看一个更简单的例子:
def apply[T, R](f: (T*) => R)(args: T*) = f(args: _*)
Run Code Online (Sandbox Code Playgroud)
这是真正的Scala代码,它可以工作,但它不适用于任何接收任意类型的函数.首先,符号T*将返回a Seq[T],这是一个回归类型的序列.然而,存在异质型序列,例如HList.
所以,首先,我们试着在HList这里使用:
def apply[T <: HList, R](f: (T) => R)(args: T) = f(args)
Run Code Online (Sandbox Code Playgroud)
那仍然在使用Scala,但我们f通过说它必须接收一个HList而不是任意数量的参数来施加一个很大的限制.假设我们使用@异构参数进行转换HList,同样的方法*从齐次参数转换为Seq:
def apply[T, R](f: (T@) => R)(args: T@) = f(args: _@)
Run Code Online (Sandbox Code Playgroud)
我们不再谈论现实生活中的Scala,而是对它的假设改进.这看起来合情合理,除了T应该是类型参数表示法的一种类型.或许,我们也可以用同样的方式扩展它:
def apply[T@, R](f: (T@) => R)(args: T@) = f(args: _@)
Run Code Online (Sandbox Code Playgroud)
对我来说,看起来这样可行,尽管这对我来说可能是天真的.
让我们考虑一个替代解决方案,一个取决于参数列表和元组的统一.让我们说Scala最终统一了参数列表和元组,并且所有元组都是抽象类的子类Tuple.然后我们可以这样写:
def apply[T <: Tuple, R](f: (T) => R)(args: T) = f(args)
Run Code Online (Sandbox Code Playgroud)
那里.制作一个抽象类Tuple是微不足道的,而元组/参数列表统一并不是一个牵强附会的想法.
在大多数静态类型语言中你不能这样做的原因是它们几乎都选择了一个仅限于统一列表的列表类型. Typed Racket是一种语言的例子,它可以讨论非统一类型的列表(例如,它有一个Listof统一列表,以及List一个静态已知长度可能不均匀的列表) - 但它仍然分配对于Racket apply,有限类型(带有统一列表),因为真实类型非常难以编码.
完整的APPLY在静态语言中很难.
在Lisp中,APPLY将函数应用于参数列表.函数和参数列表都是APPLY的参数.
APPLY可以使用任何功能.这意味着这可以是任何结果类型和任何参数类型.
APPLY采用任意长度的任意参数(在Common Lisp中,长度受特定于实现的常量值限制),具有任意和可能不同的类型.
APPLY返回由它作为参数获得的函数返回的任何类型的值.
一种类型如何在不破坏静态类型系统的情况下检查?
例子:
(apply #'+ '(1 1.4)) ; the result is a float.
(apply #'open (list "/tmp/foo" :direction :input))
; the result is an I/O stream
(apply #'open (list name :direction direction))
; the result is also an I/O stream
(apply some-function some-arguments)
; the result is whatever the function bound to some-function returns
(apply (read) (read))
; neither the actual function nor the arguments are known before runtime.
; READ can return anything
Run Code Online (Sandbox Code Playgroud)
交互示例:
CL-USER 49 > (apply (READ) (READ)) ; call APPLY
open ; enter the symbol OPEN
("/tmp/foo" :direction :input :if-does-not-exist :create) ; enter a list
#<STREAM::LATIN-1-FILE-STREAM /tmp/foo> ; the result
Run Code Online (Sandbox Code Playgroud)
现在使用REMOVE函数的示例.我们将从不同的事物列表中删除字符a.
CL-USER 50 > (apply (READ) (READ))
remove
(#\a (1 "a" #\a 12.3 :foo))
(1 "a" 12.3 :FOO)
Run Code Online (Sandbox Code Playgroud)
请注意,您也可以申请自己申请,因为申请是一项功能.
CL-USER 56 > (apply #'apply '(+ (1 2 3)))
6
Run Code Online (Sandbox Code Playgroud)
还有一个轻微的复杂因素,因为APPLY函数接受任意数量的参数,其中只有最后一个参数需要是一个列表:
CL-USER 57 > (apply #'open
"/tmp/foo1"
:direction
:input
'(:if-does-not-exist :create))
#<STREAM::LATIN-1-FILE-STREAM /tmp/foo1>
Run Code Online (Sandbox Code Playgroud)
怎么处理?
放松静态类型检查规则
限制申请
上述一个或两个必须以典型的静态类型检查编程语言完成.两者都不会给你一个完全静态检查和完全灵活的应用程序.
| 归档时间: |
|
| 查看次数: |
1407 次 |
| 最近记录: |