为什么 newtype 语法创建一个函数
Why the newtype syntax creates a function
我看这个声明:
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
这是我的理解:
1) 解析器被声明为带有类型参数的类型 a
2) 你可以通过提供解析器函数来实例化Parser,例如p = Parser (\s -> Nothing)
我观察到的是,我突然定义了一个函数名称 parse
,它能够 运行 解析器。
比如我可以运行:
parse (Parser (\s -> Nothing)) "my input"
并得到 Nothing
作为输出。
这个解析函数是如何用这个特定的签名定义的?这个函数 "know" 是如何执行给它的 Parser 的呢?希望有人能解开我的困惑。
谢谢!
首先,让我们看一下没有记录语法的解析器新类型:
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
当你写 newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
时,你引入了三件事:
一个名为 Parser
.
的类型
Parser
的术语级构造函数,名为 Parser
。这个函数的类型是
Parser :: (String -> Maybe (a, String)) -> Parser a
你给它一个函数,它把它包装在一个 Parser
- 一个名为
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
.
时具有相同的名称
How does this function "know" to execute the Parser given to it
您正在使用 parse
展开函数,然后使用 "myInput"
调用展开的函数。
我看这个声明:
newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
这是我的理解:
1) 解析器被声明为带有类型参数的类型 a
2) 你可以通过提供解析器函数来实例化Parser,例如p = Parser (\s -> Nothing)
我观察到的是,我突然定义了一个函数名称 parse
,它能够 运行 解析器。
比如我可以运行:
parse (Parser (\s -> Nothing)) "my input"
并得到 Nothing
作为输出。
这个解析函数是如何用这个特定的签名定义的?这个函数 "know" 是如何执行给它的 Parser 的呢?希望有人能解开我的困惑。
谢谢!
首先,让我们看一下没有记录语法的解析器新类型:
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
当你写 newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
时,你引入了三件事:
一个名为
Parser
. 的类型
Parser
的术语级构造函数,名为Parser
。这个函数的类型是
Parser :: (String -> Maybe (a, String)) -> Parser a
你给它一个函数,它把它包装在一个 Parser
- 一个名为
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
.
How does this function "know" to execute the Parser given to it
您正在使用 parse
展开函数,然后使用 "myInput"
调用展开的函数。