1

Haskell beginner here, sorry in advance for the dumb question. I'm coming from Python, and just wondering how I can get data (i.e. a string) out of a Haskell data type.

Let's say I have an RDF graph as used by rdf4h, and I can get an Node object out of it. This is what it looks like when I print it:

LNode (PlainL "Stories from the Italian Poets: with Lives of the Writers, Volume 1")

How can I get the string value out of this? (I.e., "Stories from the...") I searched Hoogle for :: Node -> Text but I can't seem to find anything. I also can't seem to find the appropriate function in Data.RDF.Types or anywhere similar. I'm sure there's something really obvious that I'm missing here.

Jonathan
  • 10,571
  • 13
  • 67
  • 103
  • 1
    probably not a duplicate, but have you had a start here: https://stackoverflow.com/questions/1012573/getting-started-with-haskell?rq=1 – sous2817 Mar 23 '18 at 17:32
  • I agree with @sous2817. Pattern matching is a fundamental part of the language that should be covered in the first few pages of any Haskell tutorial. If you haven't read about it yet, you probably shouldn't be asking Haskell questions here yet. – dfeuer Mar 23 '18 at 19:43
  • 3
    I'm voting to close this question as off-topic because SO is not the place to learn the very basics of a new programming language. A book or tutorial would be more appropriate. – dfeuer Mar 23 '18 at 19:44
  • Calling it a "object"... criminal – Anthony Raimondo Mar 23 '18 at 19:59
  • @AnthonyRaimondo Not really "criminal", just a terminology slip (Jono: you can simply call it "a `Node` value"). – duplode Mar 24 '18 at 01:21
  • @AnthonyRaimondo Why not call something an "object" if this term is not occupied and the concept is aligned in meaning with other usages of "object", both in programming and in everyday life? Actually, this *thing* in question may have a value, but it is not yet *the* value; we do not call functions or string literals values, do we? And we can barely destructure a value; value is dumb and terminal, unlike an *object*.    I actually go around calling things "objects" in Haskell, consciously, and I would like not to be stigmatized as a criminal (or a fool) on the basis of that alone. – Ignat Insarov Mar 24 '18 at 05:55
  • @IgnatInsarov While I agree with your broader point, we do use "value", as a catch-all term, to talk about functions, strings and things we can destructure. – duplode Mar 24 '18 at 13:04
  • @IgnatInsarov No, I would absolutely describe strings, functions, and compound structures as values. That's pretty standard. I'm also happy to call things objects in Haskell though, with the understanding that this doesn't carry so of the specific meaning from object oriented programming, but is simply the everyday or mathematical usage of the word. But object vs value as a distinction between things with structure and things that are "dumb and terminal" is a very Java-ish concept, not useful in Haskell. Object and value are mostly synonyms to me when I'm in Haskell mode. – Ben Mar 24 '18 at 13:49
  • @duplode It is very reasonable to consider all these things "values" insofar as they possess a "type". But from the point of view of actual programming, as opposed to type theorizing, I would not call a function or a string literal a value, but rather speak of the "value of a function" and the "value of a string literal" (same word — different terms, actually) while reserving other terms for syntactic representations. – Ignat Insarov Mar 24 '18 at 15:17
  • @IgnatInsarov Indeed, "value of a string literal" is entirely appropriate if you need to be explicit with respect to syntax versus semantics. I don't think we have the same issue with "value of a function", though: a Haskell function is really a value. (Also cf. [sections 1.1 and 1.3 of the Report](https://www.haskell.org/onlinereport/haskell2010/haskellch1.html#x6-100001.1) which, value versus expression distinction aside, impose basically no restrictions on what can be regarded as values.) – duplode Mar 24 '18 at 15:36
  • @duplode Yes, as I said — different terms. Suppose `f x = \y -> x + y`. Then, the value of `f 10` is a function (in the type theory sense) which value at `3` is `13` (in real analysis sense). So we have a value of a value at a value. Which is why I would not always refer to a function as a value, but only do so in type theoretic context. – Ignat Insarov Mar 24 '18 at 15:45
  • @IgnatInsarov I think we are talking about different things. You are saying "`f 10` is (or denotes, if we want to be rigorous) the value of a function (evaluated at `10`)"; I am saying "`f` is (or denotes) a value". – duplode Mar 24 '18 at 15:51
  • @duplode, I think of objects as ways to organize program state. They pretty much always have a notion of object identity. Objects show up in Haskell implementation as "heap objects". I think you could consider a value based on mutable variables and mutable arrays to be kind of objectish, but otherwise I don't think the Haskell language really has objects. – dfeuer Mar 24 '18 at 19:13
  • 1
    @dfeuer I tend to agree. The "smart object" versus "dumb value" opposition Ben addresses upthread appears to be a byproduct of taking this meaning of object as paradigmatic. – duplode Mar 25 '18 at 01:19

2 Answers2

8

The most common method to get at the fields of a data type is to pattern match on the constructors. The LValue type has the three constructors PlainL !Text, PlainLL !Text !Text, and TypedL !Text !Text.

handleLValue lvalue =
  case lvalue of
    PlainL a    -> ... do something with the value a here
    PlainLL a b -> ... do something with the values a and b here
    TypedL a b  -> ... ditto
user2297560
  • 2,953
  • 1
  • 14
  • 11
2

Here are the relevant types from Data.RDF.Types:

data Node = UNode !T.Text 
          | BNode !T.Text 
          | BNodeGen !Int 
          | LNode !LValue deriving (Generic,Show)

data LValue = PlainL !T.Text 
            | PlainLL !T.Text !T.Text 
            | TypedL !T.Text !T.Text deriving (Generic,Show)

So if you have

x = LNode (PlainL "Stories from the Italian Poets: with Lives of the Writers, Volume 1")

you just pattern-match on it:

let (LNode (PlainL t)) = x
in t
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 3
    Perhaps it should be added that, when `x` does not actually contain `PlainL t` but is, say, `PlainLL t1 t2`, the `let` above will make the program crash. Instead, a proper `case` can handle all the possible constructors. – chi Mar 23 '18 at 19:16