Haskell中用多态性替换条件的等效模式是什么?
What is the equivalent pattern in haskell for replacing conditionals with polymorphism?
我一直在探索Haskell以获得一些函数式编程经验。我希望找到能带来一些见解的模式,这样我就可以写出更好的 c++。例如,我发现将 switch 语句转换为多态代码的正常实现并不令人满意。
void HandleMessage(int type, Message m)
{
switch (type)
{
case 1:
HandleType1(m);
break;
case 2:
HandleType2(m);
break;
default:
Log("error, unhandled message type")
}
}
成为:
void HandleMessage(Type t, Message m)
{
std::unique_ptr<HandlerInterface> handler = HandlerFactory.GetHandler(t);
handler.handleMessage(m);
}
std::unique_ptr<HandlerInterface> HandlerFactory::GetHandler(Type t)
{
switch (t)
{
case 1:
return std::make_unique<HandlerType1>();
case 2:
return std::make_unique<HandlerType2>();
default:
return std::make_unique<DefaultHandler>();
}
}
这只是将开关推到工厂。它可能比第一个解决方案更好,但感觉应该有更好的解决方案。
我想知道哈斯克尔是否存在更好的模式。我知道你可以使用警卫:
handleMessage t msg
| t == 1 = handleType1 msg
| t == 2 = handleType2 msg
但这似乎并没有那么优雅。您可以将类型作为整数切换到正确的类型并进行模式匹配:
data Type = Type1 | Type2
createType t
| t == 1 = Type1
| t == 2 = Type2
handleMessage Type1 msg = handleType1 msg
handleMessage Type2 msg = handleType2 msg
同样,我们可以按下开关,但我并没有真正看到优雅的东西。我希望有几件事:
- 凝聚力:代码很好地捆绑在一起。
- 添加新句柄几乎不需要样板。没有一个是首选!
- 很高兴拥有:缺少特定类型的处理程序将是一个编译错误。
你的 Haskell 解决方案是第一个C++片段的近似副本。它只是因为 Haskell 的更简洁的语法而看起来更好,但它做同样的事情。实际上,一个确切的C++等价物是
enum Type { Type1, Type2 };
...
Type getType(int type) {
switch (type) {
case 1: return Type1;
case 2: return Type2;
...
...
switch (getType(type)) {
case Type1: // etc etc
正如你所看到的,没有太多精彩和令人兴奋的函数式编程正在进行。事实上,函数式编程是关于以函数作为第一类值的编程。您的示例中没有任何。
让我们稍微改变一下。
....
handler Type1 = handleType1
handler Type2 = handleType2
所以现在handler
是一个原始的高阶函数。它获取一个 Type 并返回另一个函数。这仍然不多,但这转化为这样C++:
void handleType1(Message);
void handleType2(Message);
auto getHandler(Type type) {
switch(type) {
case Type1: return handleType1;
case Type2: return handleType2;
....
因此,您不是返回一个对象,而是返回一个函数。这不是巧合。对象只是一堆函数(它的方法)。具有一个方法的对象只是一个函数!
等等,数据呢?对象不是由方法和数据组成的吗?它是,但它的数据可以绑定在一个函数中(想想lambda或std::bind)。普通C++函数(函数指针)无法捕获上下文,但您只需使用 lambda 和 std::function。
所以我想这个例子最终不会带来太多的见解。代替对象,使用函数,仅此而已。
您可以在 Int 上进行模式匹配:
createType 1 = Type1
createType 2 = Type2
createType _ = error("error, unhandled message type")
handleMessage n msg = handleType (createType n) msg
handleType Type1 msg = doSome...
handleType Type2 msg = doSome2...
但是如果你不想这样做,你可以直接对 Types 进行模式匹配:
handleType Type1 msg = handle1 msg
handleType Type2 msg = handle2 msg
但更好的是使用类型类:
class Handler a where
handleMsg :: a -> String -> IO ()
data Type = Type1 | Type2
instance Handler Type where
handleMsg Type1 = handle1
handleMsg Type2 = handle2
handle1 msg = putStrLn $ "handle1 " ++ msg
handle2 msg = putStrLn $ "handle2 " ++ msg
main = do
handleMsg Type1 "error 1"
handleMsg Type2 "error 2"
- libc++ 的 std::basic_string 的 16 字节对齐模式背后的原因是什么?
- Haskell中用多态性替换条件的等效模式是什么?
- 最简单的事件设计模式是什么
- 在发布模式下崩溃,但如果可调试为 true - 不是..什么是可能的问题
- 使用来自不同类的同名函数;这是什么模式
- 从C 中的函数中动态分配的缓冲区返回的最佳模式是什么?
- 解析 HTTP 的摘要式身份验证的正确正则表达式模式是什么?
- 打开文件的正确模式是什么,以便 seekp() 的工作方式与在默认模式下打开的文件相同
- 这种模式是什么意思?新建(&条目[num_entries])项目;
- 与保留模式GUI相比,使用直接模式GUI的性能含义是什么?
- 一般来说,使用Qt Creator,是什么导致程序在调试模式下编译时正确运行,但在发布模式下崩溃
- DNA模式匹配中最快的算法是什么
- 使用具有返回值的访客模式实现 AST 的最佳方法是什么?
- lock_guard始终拥有引用互斥锁的锁定模式是什么意思
- 一些数据库持久性设计模式是什么
- 这个设计模式是什么?如何使用它
- 使用"Memory Mapped Files"读取大XML数据的模式是什么?
- 使用asio::async_read的正确模式是什么?
- c++的习惯用法/模式是什么?
- 迭代地图和删除项目的最佳模式是什么?