【问题标题】:SML conversions to HaskellSML 到 Haskell 的转换
【发布时间】:2011-04-08 20:06:02
【问题描述】:

关于将 SML 代码转换为 Haskell 的几个基本问​​题。
1) 我习惯于在 SML 代码中嵌入本地表达式,例如测试表达式、打印等,这些表达式在加载(评估)代码时执行本地测试和输出。 在 Haskell 中,似乎获得结果(评估)的唯一方法是在一个模块中添加代码,然后在另一个模块中转到 main 并添加一些东西来调用和打印结果。

这是对的吗?在 GHCi 中,我可以输入表达式并查看结果,但这可以自动化吗? 每次测试评估都必须进入顶级 main 对我来说似乎很不方便 - 也许只需要改变我的懒惰范式。

2) 在 SML 中,我可以对返回的结果进行模式匹配和统一,例如

val myTag(x) = somefunct(a,b,c);

并在匹配后获取 x 的值。

我可以在 Haskell 中轻松地做类似的事情,而无需编写单独的提取函数吗?

3) 如何使用元组参数进行构造函数,即 uncurried。
在 SML 中:

数据类型事物 = Int * Int 的信息;

但在 Haskell 中,我尝试过;

数据事物 = 信息 (Int Int)

失败了。 (“Int 应用于类型中的参数过多:A few Int Int”) 咖喱版效果很好,

数据事物 = Info Int Int

但我想要不咖喱。

谢谢。

【问题讨论】:

    标签: haskell sml


    【解决方案1】:
    • 这个问题有点不清楚——你问的是如何评估 Haskell 中的函数?

    如果是关于在纯代码中插入调试和跟踪,这通常只在调试时需要。要在 Haskell 中执行此操作,您可以使用 Debug.Trace.tracein the base package

    如果您担心调用函数,Haskell 程序会按照依赖顺序从main 向下评估。但是,在 GHCi 中,您可以导入模块并调用您希望的任何顶级函数。

    • 如果您愿意,您可以将原始参数作为函数结果的一部分返回给函数,例如使用元组:

      f x = (x, y) where y = g a b c

    或者您的意思是返回一个值或另一个值?然后使用带标签的联合(sum-type),比如Either

    f x = if x > 0 then Left x
                    else Right (g a b c)
    
    • 如何使用元组参数创建构造函数,即 SML 中的非curried

    使用(,) 构造函数。例如

     data T = T (Int, Int)
    

    虽然更像 Haskell 会是:

     data T = T Int Bool
    

    这些在实践中可能应该是严格的领域:

     data T = T !Int !Bool
    

    【讨论】:

    • 是的,我想它可能正在调试,但也可能是任何有效的输出。我猜你总结为一切都是自上而下的,所以改变整体结果的唯一方法是不能同时在顶部和底部工作......
    • 您的第二部分与您回复的不同 - RHS 函数返回一个标记的数据类型,然后表达式将其与构造函数(类型)匹配,统一在 LHS 变量(x)上,并且丢弃构造函数。然后表达式的结果是提取的未包装的“x”值。每种数据类型都不需要特殊的解包函数,统一就可以了。
    • SML 不会对值进行神奇的“统一”。你的意思是命名LHS?如果是这样,“@”符号将起作用:f x@(_,y) = x
    • @Guthrie:如果我理解正确,您是在询问变量声明中的模式匹配,而不是函数参数中的模式匹配。这在 Haskell 中运行良好:let MyTag x = somefunct a b c in frob x。 (请注意,构造函数需要以大写字母开头,并且 Haskell 中的所有内容都是柯里化的——你几乎永远不会看到用于捆绑参数的元组,除非元组表示某种东西 [比如点]。)
    【解决方案2】:
    1. Debug.Trace 允许您打印内联调试消息。但是,由于这些函数使用 unsafePerformIO,因此与 SML 等按值调用语言相比,它们的行为方式可能出乎意料。

    2. 我认为@ 语法正是您在这里寻找的:

      data MyTag = MyTag Int Bool String
      
      someFunct :: MyTag -> (MyTag, Int, Bool, String)
      someFunct x@(MyTag a b c) = (x, a, b, c) -- x is bound to the entire argument
      
    3. 在 Haskell 中,元组类型用逗号分隔,例如,(t1, t2),所以你想要的是:

      data Thing = Info (Int, Int)
      

    【讨论】:

    • 对于第二个,假设该函数返回两个变量的数据类型,一个 tagStr(s) 或一个 tagInt(x),我想查找一些东西(可能是符号表值等) 并仅返回这两种类型中的一种 - 并对标签类型进行类型检查,然后只使用返回的(未包装的)实际数据值“x”。 SML 代码只是如上所示,统一在 myTag(x) 上,从而设置“x”值。我当然可以得到返回值,然后在明确的第二步中解开它——但它在 SML 中工作得非常好,我想知道最好的 Haskell'ish 习语是什么。谢谢。
    • guthrie,使用例如Haskell 中的Either 数据类型。 Left String | Right Int -- 或其他求和类型。
    【解决方案3】:

    阅读其他答案,我想我可以提供更多示例和一个建议。

    data ThreeConstructors = MyTag Int | YourTag (String,Double) | HerTag [Bool]
    
    someFunct :: Char -> Char -> Char -> ThreeConstructors
    
    MyTag x = someFunct 'a' 'b' 'c'
    

    这类似于“let MyTag x = someFunct a b c”示例,但它是模块的顶层。

    正如您所注意到的,Haskell 的顶层可以定义命令,但无法仅仅因为您的模块已被另一个模块导入而自动运行任何代码。这与 Scheme 或 SML 完全不同。在 Scheme 中,文件被解释为逐个执行,但 Haskell 的顶层只是声明。因此库不能做正常的事情,比如加载时运行初始化代码,它们必须提供“pleaseRunMe :: IO ()”类型的命令来进行任何初始化。

    正如您所指出的,这意味着运行所有测试需要一些样板代码才能将它们全部列出。您可以在 hackage 的 Testing 组下查找需要帮助的库,例如 test-framework-th

    【讨论】:

      【解决方案4】:

      对于#2,是的,Haskell 的模式匹配做同样的事情。 letwhere 都进行模式匹配。你可以这样做

      let MyTag x = someFunct a b c
      in ...
      

      ...
      where MyTag x = someFunct a b c
      

      【讨论】:

        猜你喜欢
        • 2020-08-23
        • 2013-12-23
        • 2020-08-15
        • 2020-08-15
        • 1970-01-01
        • 2012-02-17
        • 1970-01-01
        • 1970-01-01
        • 2021-12-24
        相关资源
        最近更新 更多