guthrie
guthrie

Reputation: 4609

SML conversions to Haskell

A few basic questions, for converting SML code to Haskell.
1) I am used to having local embedded expressions in SML code, for example test expressions, prints, etc. which functions local tests and output when the code is loaded (evaluated). In Haskell it seems that the only way to get results (evaluation) is to add code in a module, and then go to main in another module and add something to invoke and print results.

Is this right? in GHCi I can type expressions and see the results, but can this be automated? Having to go to the top level main for each test evaluation seems inconvenient to me - maybe just need to shift my paradigm for laziness.

2) in SML I can do pattern matching and unification on a returned result, e.g.

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

and get the value of x after a match.

Can I do something similar in Haskell easily, without writing separate extraction functions?

3) How do I do a constructor with a tuple argument, i.e. uncurried.
in SML:

datatype Thing = Info of Int * Int;

but in Haskell, I tried;

data Thing = Info ( Int Int)

which fails. ("Int is applied to too many arguments in the type:A few Int Int") The curried version works fine,

data Thing = Info Int Int

but I wanted un-curried.

Thanks.

Upvotes: 3

Views: 532

Answers (4)

Chris Kuklewicz
Chris Kuklewicz

Reputation: 8153

Reading the other answers, I think I can provide a few more example and one recommendation.

data ThreeConstructors = MyTag Int | YourTag (String,Double) | HerTag [Bool]

someFunct :: Char -> Char -> Char -> ThreeConstructors

MyTag x = someFunct 'a' 'b' 'c'

This is like the "let MyTag x = someFunct a b c" examples, but it is a the top level of the module.

As you have noticed, Haskell's top level can defined commands but there is no way to automatically run any code merely because your module has been imported by another module. This is entirely different from Scheme or SML. In Scheme the file is interpreted as being executed form-by-form, but Haskell's top level is only declarations. Thus Libraries cannot do normal things like run initialization code when loaded, they have to provide a "pleaseRunMe :: IO ()" kind of command to do any initialization.

As you point out this means running all the tests requires some boilerplate code to list them all. You can look under hackage's Testing group for libraries to help, such as test-framework-th.

Upvotes: 1

newacct
newacct

Reputation: 122449

For #2, yes, Haskell's pattern matching does the same thing. Both let and where do pattern matching. You can do

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

or

...
where MyTag x = someFunct a b c

Upvotes: 1

Don Stewart
Don Stewart

Reputation: 137977

  • This question is a bit unclear -- you're asking how to evaluate functions in Haskell?

If it is about inserting debug and tracing into pure code, this is typically only needed for debugging. To do this in Haskell, you can use Debug.Trace.trace, in the base package.

If you're concerned about calling functions, Haskell programs evaluate from main downwards, in dependency order. In GHCi you can, however, import modules and call any top-level function you wish.

  • You can return the original argument to a function, if you wish, by making it part of the function's result, e.g. with a tuple:

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

Or do you mean to return either one value or another? Then using a tagged union (sum-type), such as Either:

f x = if x > 0 then Left x
                else Right (g a b c)
  • How do I do a constructor with a tuple argument, i.e. uncurried in SML

Using the (,) constructor. E.g.

 data T = T (Int, Int)

though more Haskell-like would be:

 data T = T Int Bool

and those should probably be strict fields in practice:

 data T = T !Int !Bool

Upvotes: 5

acfoltzer
acfoltzer

Reputation: 5618

  1. Debug.Trace allows you to print debug messages inline. However, since these functions use unsafePerformIO, they might behave in unexpected ways compared to a call-by-value language like SML.

  2. I think the @ syntax is what you're looking for here:

    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. In Haskell, tuple types are separated by commas, e.g., (t1, t2), so what you want is:

    data Thing = Info (Int, Int)
    

Upvotes: 4

Related Questions