【问题标题】:Why the newtype syntax creates a function为什么 newtype 语法会创建一个函数
【发布时间】:2020-02-19 14:28:19
【问题描述】:

我看看这个声明:

newtype Parser a = Parser { parse :: String -> Maybe (a,String) }

这是我的理解:

1) Parser 被声明为带有类型参数a 的类型

2) 您可以通过提供解析器函数来实例化 Parser,例如 p = Parser (\s -> Nothing)

我观察到突然我定义了一个函数名称parse,它能够运行解析器。

例如,我可以运行:

parse (Parser  (\s -> Nothing)) "my input" 

并得到Nothing 作为输出。

这个解析函数是如何用这个特定的签名定义的?这个函数如何“知道”执行给它的 Parser?希望有人能解开我的困惑。

谢谢!

【问题讨论】:

  • 它是自动创建 accessor 函数的 record 语法。

标签: haskell newtype


【解决方案1】:

当你写newtype Parser a = Parser { parse :: String -> Maybe (a,String) } 时,你介绍了三件事:

  1. 一个名为Parser的类型。

  2. Parsers 的术语级构造函数,名为 Parser。这个函数的类型是

Parser :: (String -> Maybe (a, String)) -> Parser a

你给它一个函数,它把它包装在一个Parser

  1. 一个名为parse 的函数,用于删除Parser 包装器并取回您的函数。这个函数的类型是:
parse :: Parser a -> String -> Maybe (a, String)

查看ghci

Prelude> newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
Prelude> :t Parser
Parser :: (String -> Maybe (a, String)) -> Parser a
Prelude> :t parse
parse :: Parser a -> String -> Maybe (a, String)
Prelude>

术语级别的构造函数 (Parser) 和删除包装器的函数 (parse) 都是任意名称,不需要匹配类型名称,这一点毫无意义。例如,常见的写法是:

newtype Parser a = Parser { unParser :: String -> Maybe (a,String) }

这清楚地表明unParse 删除了解析函数周围的包装。但是,我建议在使用 newtypes 时,您的类型和构造函数具有相同的名称。

这个函数如何“知道”执行给它的 Parser

您正在使用parse 解包函数,然后使用"myInput" 调用解包函数。

【讨论】:

    【解决方案2】:

    首先,让我们看一下没有记录语法的解析器 newtype:

    newtype Parser' a = Parser' (String -> Maybe (a,String))
    

    这个类型的作用应该很明显:它存储了一个函数String -> Maybe (a,String)。要运行这个解析器,我们需要创建一个新函数:

    runParser' :: Parser' -> String -> Maybe (a,String)
    runParser' (Parser' p) i = p i
    

    现在我们可以运行像runParser' (Parser' $ \s -> Nothing) "my input" 这样的解析器了。

    但现在请注意,由于 Haskell 函数是柯里化的,我们可以简单地删除对输入 i 的引用来获得:

    runParser'' :: Parser' -> (String -> Maybe (a,String))
    runParser'' (Parser' p) = p
    

    这个函数完全等价于runParser',但是你可以换个思路:它不是显式地将解析器函数应用于值,而是简单地接受一个解析器并从中获取解析器函数;然而,由于柯里化,runParser'' 仍然可以与两个参数一起使用。

    现在,让我们回到原来的类型:

    newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
    

    您的类型和我的类型之间的唯一区别是您的类型使用record syntax,尽管可能有点难以识别,因为newtype 只能有一个字段;此记录语法自动定义一个函数parse :: Parser a -> (String -> Maybe (a,String)),它从Parser a 中提取String -> Maybe (a,String) 函数。希望其余的应该是显而易见的:由于柯里化,parse 可以使用两个参数而不是一个,这只是运行存储在Parser a 中的函数的效果。也就是说,你的定义完全等同于下面的代码:

    newtype Parser a = Parser (String -> Maybe (a,String))
    
    parse :: Parser a -> (String -> Maybe (a,String))
    parse (Parser p) = p
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-03
      • 2019-12-05
      • 1970-01-01
      • 2020-02-03
      • 2014-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多