繁体   English   中英

Haskell:作为数据类型

[英]Haskell: Function as Data type

我觉得学习haskell的思维障碍之一是data有时将功能定义为数据。

data Person = Person {
  name :: String,
  age  :: Int
}

这是直观的,类似于其他语言。 但在

newtype StateT s m a = StateT {
  runStateT :: s -> m (a,s)
}

这基本上是在调用函数s->m (a,s) “数据”

我很容易理解,在高阶函数中,“函数”确实作为数据传递。 但是在类型定义中,使用函数定义类型是非常令人惊讶的。

所以我的问题是:这会给Haskell类型系统带来表现力吗? 所有这些背后的理论是什么?

这只是围绕一个功能的包装。

foo :: String -> [(Int, String)]
foo xs = zip [1..] (map pure xs)

fooState :: StateT String [] Int
fooState = StateT foo

数据构造函数StateT接受一个参数,即类型s -> m (a, s)的函数,并返回StateT sma类型的值。 在这里,我们有

  • s ~ String
  • m ~ []
  • a ~ Int

由于foo的声明类型。


与Python这样的语言中的函数引用确实没有太大区别。 (请注意,此处的foo类型与Haskell示例中的类型略有不同,但是要注意将foo引用传递给StateT.__init__的想法)。

class StateT:
   def __init__(self, f):
       self.runStateT = f

def foo(xs):
    return enumerate(xs)

x = StateT(foo)

函数与其他任何值一样,具有类型,并且可以将其作为参数传递。 数据类型的字段也可以存储函数,这又与使用其他值没有什么不同:

GHCi> :t ("foo", "bar")
("foo", "bar") :: ([Char], [Char])
GHCi> :t (reverse, drop 2)
(reverse, drop 2) :: ([a1] -> [a1], [a2] -> [a2])

从这个角度来看,...之间没有本质区别。

newtype MyInt = MyInt { getMyInt :: Int }

...和:

newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }

这会为Haskell类型系统带来表现力吗?

这是这样做的两种方法。 首先,函数类型的包装和类型同义词允许编写较少混乱的类型签名。 例如...

withStateT :: (s -> s) -> StateT s m a -> StateT s m a

...比以下内容好得多:

withStateT :: (s -> s) -> (s -> m (a, s)) -> (s -> n (a, s))

其次,新型包装器使为函数类型编写类实例变得可行-例如,没有它们,我们将没有StateT拥有的至关重要的实例( FunctorApplicativeMonadMonadTrans等)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM