ruby Twilio文本

.rb
require 'rest-client'

TWILIO_ACCOUNT_SID = "YOUR_TWILIO_ACCOUNT_SID"
TWILIO_AUTH_TOKEN = "YOUR_TWILIO_AUTH_TOKEN"
TWILIO_NUMBER = 'YOUR_TWILIO_NUMBER'

RestClient.post "https://#{TWILIO_ACCOUNT_SID}:#{TWILIO_AUTH_TOKEN}@api.twilio.com/2010-04-01/Accounts/#{TWILIO_ACCOUNT_SID}/SMS/Messages", {
  "From" => TWILIO_NUMBER,
  "To" => '+19712227154',
  "Body" => "BEWD Rocks!",
}

ruby Twilio Sinatra

demo_app.rb
# Need the Sinatra Library to make a web app!
require 'sinatra'

# This is the URL that can be used for the Voice URL on your Twilio Number
post '/messages' do
  content_type 'text/xml'
  "<Response>
    <Message>This is an SMS reply.</Message>
  </Response>"
end

# This is the URL that can be used for the Voice URL on your Twilio Number
post '/voice' do
  content_type 'text/xml'
  "<Response>
    <Say>This is a text-to-speach block.</Say>
    <Play>http://cdn.wawra.co/sw.mp3</Play>
  </Response>"
end
interactive.rb
require 'twilio-ruby'

client = Twilio::REST::Client.new "YOUR TWILIO SID", "YOUR TWILIO TOKEN"

# Get a list of messages sent to a given number...
messages = client.account.messages.list to: "YOU TWILIO NUMBER"

# Now print out each message
messages.each do |msg|
  puts "#{msg.from}:   #{msg.body}"
end

# Get all of the phone numbers:
numbers = messages.collect do |msg|
  msg.from
end

# For each number call back using the '/voice' action in the sinatra application.
numbers.each do |num|
  client.account.calls.create(to: num, from: "YOU TWILIO NUMBER", body: "http://server-with-sinatra-app/voice"
end

ruby Twilio控制器

twilio_controller.rb
require 'twilio-ruby'
require 'sanitize'

class TwilioController < ApplicationController

  def ivr_welcome
    response = Twilio::TwiML::VoiceResponse.new do |r|
      phrase = "Welcome, Please Enter Survey Number"
      r.say(phrase, voice: 'alice', language: 'en-GB')
      gather = Twilio::TwiML::Gather.new(num_digits: '1', action: ivr_survey_path)
      r.append(gather)
    end
    render xml: response.to_s
  end

  def survey
    survey_id = params[:Digits]
    @survey = Survey.find_by(id: survey_id)
    if @survey.present?
      session[params[:Caller]] = {}
      questions = @survey.questions.unanswered
      phrase = "All the questions will be asked one bye one, Please punch in your response"
      questions.each do |question|
      	session[params[:Caller]][question.id] = question.question
      end
      response = Twilio::TwiML::VoiceResponse.new do |r|
        r.say(phrase, voice: 'alice', language: 'en-GB')
        r.redirect(ivr_questions_path)
      end
    else
      phrase = "We can't find any survey with given number, Goodbye"
      return twiml_say_and_hangup(phrase)
    end
    render xml: response.to_s
  end

  
  def questions
    questions = session[params[:Caller]]
    if questions.present? && questions.count > 0
      question = questions.first
      message = "#{question[1]}. Press 1 for yes, Press 2 for 'no'"
      response = Twilio::TwiML::VoiceResponse.new do |r|
        gather = Twilio::TwiML::Gather.new(num_digits: '1', action: ivr_answer_path(question_id: question[0]))
        gather.say(message, voice: 'alice', language: 'en-GB', loop: 10)
        r.append(gather)
      end
    else
      phrase = "Thank you, The survey has been ended, Goodbye."
      reset_session
      return twiml_say_and_hangup(phrase)
    end
    render xml: response.to_s
  end

  def answer
    question = Question.find_by(id: params[:question_id])
    case params[:Digits]
      when '1'
        question.yes!
        session[params[:Caller]].delete(question.id.to_s)
      when '2'
        question.no!
        session[params[:Caller]].delete(question.id.to_s)
      else
      message = "Please Enter Valid Input"
    end
    response = Twilio::TwiML::VoiceResponse.new do |r|
      r.redirect(ivr_questions_path)
    end
    render xml: response.to_s
  end

  end

  private

  def twiml_say_and_hangup(phrase)
    response = Twilio::TwiML::VoiceResponse.new do |r|
      r.say(phrase, voice: 'alice', language: 'en-GB')
      r.hangup
    end
    render xml: response.to_s
  end
end

ruby jsgf到alexa

jsgf_alexa.rb
require 'jsgf'

module JSGF
    class Grammar
        # Convert a {Grammar} into a set of sample utterances for Alexa
        # @option slots [Array]         The rule names that should be used as slot names
        # @return [Array<String>]       An array of the example strings
        def to_examples(slots:[])
            raise StandardError, "The grammar must have at least one root rule" unless roots
            raise StandardError, "The grammar must contain at least one public rule" if roots.empty?

            roots.flat_map {|name, rule| expand_atom(rule, ["#{name}Intent"], slots:slots) }
        end

        # Expand an {Atom} into an array of strings
        # @return [Array]
        def expand_atom(atom, prefix=[], slots:[], slot_name:nil)
            case atom
                when JSGF::Alternation
                    atom.map {|a| expand_atom(a, prefix, slots:slots, slot_name:slot_name) }
                when JSGF::Atom
                    if prefix.first.is_a?(Array)
                        prefix.map {|pref| expand_atom(atom, pref, slots:slots, slot_name:slot_name) }
                    else
                        atom_name = atom.to_s
                        atom_name = "{#{atom_name}|#{slot_name}}" if slot_name && !atom_name.empty?
                        atom_name = nil if atom_name.empty?
                        [[*prefix, atom_name].compact.join(' ')]
                    end
                when JSGF::Rule, Array
                    atom.reduce(prefix) {|memo, a| expand_atom(a, memo, slots:slots, slot_name:slot_name)}
                when Hash
                    reference_name = atom[:name]
                    slot_name = slots.include?(reference_name) ? reference_name : nil
                    expand_atom(rules[atom[:name]], prefix, slots:slots, slot_name:slot_name)
                else
                    raise "Unknown atom #{atom}"
            end
        end
    end
end

# Example grammar. Replace this with your actual grammar.
grammar = JSGF.grammar 'ColorExpert' do
    rule MyColorIs: 'my favorite color is :Color'
    rule Color: %w{green red blue orange gold silver yellow black white}
end

File.write('utterances.txt', grammar.to_examples(slots:['Color']))

ruby 贝叶斯垃圾邮件过滤器

bayes.rb
#!/usr/bin/env ruby
### Requires
require 'yaml'
require 'progressbar'
require 'iconv'

### Globals
$SPAM_CORPUS="/home/zach/tmp/spam/new/"
$HAM_CORPUS="/home/zach/tmp/ham/new/"
$SPAM_DB="/home/zach/Projects/bayes/spam.yaml"
$HAM_DB="/home/zach/Projects/bayes/ham.yaml"

### Methods ##################################################

### Training
def trainHamSpam(hamLocation, spamLocation)  
  hamDirCount = Dir.entries(hamLocation).length()
  hpbar = ProgressBar.new("Training Ham", hamDirCount)
  hamHashes = Hash.new
  checkedHamWords = 0
  Dir.foreach(hamLocation) do |f|
    loc = hamLocation + f
    if File.file?(loc)
      results = processFile(loc, hamHashes)
      hamHashes = hamHashes.merge(results[:hash])
      checkedHamWords = checkedHamWords + results[:wordCount]
      hpbar.inc
      end
  end
  hpbar.finish

  spamDirCount = Dir.entries(spamLocation).length()
  spbar = ProgressBar.new("Training Spam", spamDirCount)
  spamHashes = Hash.new
  checkedSpamWords = 0
  Dir.foreach(spamLocation) do |f|
    loc = spamLocation + f
    if File.file?(loc)
      results = processFile(loc, spamHashes)
      spamHashes = spamHashes.merge(results[:hash])
      checkedSpamWords = checkedSpamWords + results[:wordCount]
      spbar.inc
    end
  end
  spbar.finish


  return {:ham => hamHashes, :spam => spamHashes}
end

def processFile(file, hash)
  wordCount = 0
  f = File.open(file, 'r')
  f.each_line { |line|
    begin
      # http://po-ru.com/diary/fixing-invalid-utf-8-in-ruby-revisited/
      ic = Iconv.new('UTF-8//IGNORE', 'UTF-8') 
      line = ic.iconv(line)
      words = line.split
    words.each { |w|
      wordCount = wordCount + 1
      if hash.has_key?(w)
        hash[w] = hash[w] + 1
      else
        hash[w] = 1
      end
    }
    rescue ArgumentError=>e
      puts "Error: #{e}"
    end
  }
  return {:hash => hash, :wordCount => wordCount}
end

### Dbs
def writeDb(data, db)
  f = File.open(db, 'w')
  f.puts data.to_yaml
  f.close()
end
  
def readDb(db)
  hash = YAML::load(File.open(db))
end
  
### Utils
def wordCount(fileName)
  f = File.open(fileName, 'r')
  a = Array.new
  fileName.each_line {|line|
    words = line.split
    words.each { |w|
      a.push(w)
    }
  }
  f.close()
  return a.length()
end

### Judging
def judgeFile(file, spam, ham)
  wordsHash = Hash.new
  f = File.open(file, 'r')
  lineCount = wordCount(file)
  lpbar = ProgressBar.new("Scanning", lineCount)
  f.each_line {|line|
    lpbar.inc
    words = line.split()
    words.each {|w|
      result = judgeWord(w, spam, ham)
      wordsHash[w] = [result[:prob], result[:abs]]
    }
  }
  lpbar.finish
  return combinedProbability(wordsHash.sort {|a,b| a[2]<=>b[2]}[0,15])
end

def combinedProbability(wordsHash)
  mult = 1
  diff = 1
  wordsHash.each do |key, value|
    mult = mult * value[0]
    diff = diff * (1 - value[0])
  end
  return mult / (mult + diff)
end

def judgeWord(word, spam, ham)
  if spam.has_key?(word)
    spam_occurrences = spam.fetch(word)
   else
      spam_occurrences = 0
  end
  if ham.has_key?(word)
    ham_occurrences = ham.fetch(word) * 2
    else
      ham_occurrences = 0
  end

  if spam_occurrences + ham_occurrences > 5
    spam_portion = spam_occurrences.to_f / spam.length().to_f
    ham_portion = ham_occurrences.to_f / ham.length().to_f
    spam_min = [1, spam_portion].min()
    ham_min = [1, ham_portion].min()
    min_sum = spam_min + ham_min
    ratio = spam_min / min_sum
    ratio_min = [0.99, ratio].min()
    prob_spam = [0.01, ratio_min].max()
    abs_spam = (0.5 - prob_spam).abs()
  else
    prob_spam = 0.5
    abs_spam = 0.0
  end
  return {:prob => prob_spam, :abs => abs_spam}
end

### Main
if ARGV.length !=1 or ARGV[0] == '-h' or ARGV[0] == '--help'
  puts __FILE__ + " FileToTest"
  puts "-h or --help for help"
  puts "-t or --train to train"
elsif ARGV[0] == '-t' or ARGV[0] == '--train'
  puts "Training..."
  hashes = trainHamSpam($HAM_CORPUS, $SPAM_CORPUS)
  writeDb(hashes[:spam], $SPAM_DB)
  writeDb(hashes[:ham], $HAM_DB)
else
  spam = readDb($SPAM_DB)
  ham = readDb($HAM_DB)
  result = judgeFile(ARGV[0], spam, ham)
  if result > 0.991
    puts "#{ARGV[0]} - #{result} - Probably spam"
  else
    puts "#{ARGV[0]} - #{result} - Probably ham"
  end
end

ruby 分类

.rb
require 'classifier-reborn'
#To speed up processing power, I also had to install the following libaries
#GNU GSL (using Homebrew)
#rb-gsl (using RubyGem)
#Technically this is all under the GPL license (please read it here: https://www.gnu.org/licenses/gpl-3.0.en.html)

lsi = ClassifierReborn::LSI.new

strings = ["A dumb oven doesn't deserve credit, but a 'smart' oven does. Machine capabilities are constantly increasing, meaning they are doing more and more of the stuff that was traditionally reserved to humans. So...as a result, they deserve more of the credit. The long-divison algorithm, hm, I would guess it'd dependent on who's performing the algorithm. If a human did it, good job. If you have the calculator perform the long-division algorithm for you (like I reluctantly do), well...the calculator gets the credit for the math problem.","I guess we're back to 'agree to disagree' :slightly_smiling_face: i have no way to understand giving credit for a long-division problem to either a calculator, or to the long-division algorithm","tra38 so, by that reasoning, would you give credit for baking bread to an oven? (if i'm slipping back into the argument, apologies. maybe i just can't pin down the cause of my confusion.) and indulge me only one more example: would you give credit to the long-division algorithm for correctly producing the right answer?","Only if it's some sort of fancy oven that can self-regulate it's own temperature (as opposed to the baker continually checking the temp manually and adjusting the heat via gas-jet or adding/subtracting wood)."," I am concerned about the ethics of giving AIs credit for the same reason I'm concerned about the ethics of giving humans credit. Just like a human wrote something and should get credit for it...the AI 'generated' text and thus should get credit for it. I don't support treating algorithms as 'mere tools' to be used, but as their own external entities that are stand-alone and work independently of their creators, and being pro-'AI credit' logically follows from that worldview.(I also tend to be anti-AI, and so arguing for AI credit is in some way an indirect argument against pro-AI views that sees algorithms as tools to be used and abused.)","Lather, rinse, repeat.","tra38 while still honoring the agree-to-disagree truce, i'm curious. if it doesn't matter to you whether something is self-conscious, and you're concerned more with outcomes, why are you so concerned about the ethics of giving AIs credit?","@michaelpaulukonis: It doesn't matter to me whether something is self-conscious. For me, I care about other factors (Are the machines being productive members of society? Are their capabilities equal to or better than the human race? Are they intelligent, creative, innovative etc.?) Self-awareness and resemblance to humanity does not enter into my calculations at all. But *other people* (especially science fiction fans and non-technical laymen) do care about these sort of factors, and I'd want to figure out whether machines could meet their criteria. After all, if the US government wants to pass a law mandating humans to give moral considerations to certain robots, they are more likely to trust @danbernier's criteria than my own. So it's important to grapple with these concepts...if only because other humans want to grapple with these concepts.","i'm not saying suffering is a hallmark of being human - i'm saying it's a good criteria for whether an entity deserves moral consideration. it's an ethics question, not a test for intelligence.","I'm not convinced that suffering is a hallmark of being human. Say there's a person who's lived a great life - toast never burnt, water always at the right temperature, etc etc etc. They've never suffered. Perhaps they can't create art. But are they in-human? Ditto for self-consciousness - it's not an inescapable part of intelligence.","i think i'm the one that keeps bringing up suffering. i don't see the similarity to IQ tests that require cultural knowledge, though - can you clarify?","@tr38 - why does it even matter if some is self-conscious? There seems to be an assumption that 'artificial intelligence' will be recognizably human intelligence, instead of some other form of intelligence (say an octopus). And quite frankly all this talk about 'suffering' seems to be like IQ tests that require candidates to know what baseball and the president is. Perhaps that's true of many Americans, but you can't judge the intelligence of somebody in a remote Kalihari village with such criteria. Nor do neural-typical strictures that fail to recognize all humans work for non-human intelligences. This is probably why I like my generative texts to not worry about looking like 'normal' literature.","i get that tension, tra38 - we can't yet know if something is self-conscious, so it's tempting to settle for a proxy measure: something objective, knowable. but as you point out, we don't have any options like that right now. and anyway, proxy measures are tricky: it's easy, and dangerous, to forget that they're not what you _really_ want to measure, and using the wrong one can steer you seriously off-course, like using lines of code as a measure of programmer productivity. for criteria, i'd rather hang on to actual-self-consciousness, because i think it's the best and clearest criterion. then, we can a) keep researching cognition, and b) argue over proxy measures in the meantime.","@danbernier: How do you measure if something is actually conscious/self-conscious? Right now, since we can't peer into our own brains, our only recourse is to look at the external behavior of an entity, and assume that if the entity acts as though it is conscious, it must be conscious. This approach, of course, wouldn't work in the case of evaluating a machine. Can the 'Chinese room' be conscious? If I program a bot to convincingly claim to be able to suffer, and be able to provide proof of that, then does it actually 'feel' that pain? Or is it just a clever parlor trick, just like ELIZIA, merely relying on  apophenia and human empathy to succeed? Maybe we can represent the bot as a state machine and that it 'suffers' when the bot is set to the 'suffering' mode. But is that 'actually' feeling pain? Or is it just another parlor trick? Since the process of identifying consciousness/self-consciousness is subjective and prone to error (either us declaring a bot as being conscious when it's not...or us denying a bot's consciousness), I'd rather prefer a more objective standard, for moral consideration. I don't really know what that objective standard  could be though, other than labor or 'free/unpredictable will'.","Can there be a fully-conscious person who cannot suffer? Such as a sociopath (no emotions?) with leprosy (no physical pain) ?","i keep coming back to the capacity for suffering. a car that's driven too hard, and not well-maintained, falls apart, but we don't feel bad for it, because it can't suffer. if the car could sense itself, then maybe it _could_ suffer, and then in that case, we'd have more of a moral obligation to take better care of it. if i'm right about all that, then, @tra38, i think the difference between a Narrow AI & a general AI is much bigger than the difference between a plumber and a doctor, because the Narrow AI probably isn't self-conscious, so probably can't suffer, so we probably don't owe it moral consideration.","related: i've been reading about/playing with the Markov Cluster Algorithm. you feed it a sparse matrix of items, and their similarity to each other. it interprets this as a proximity graph, and then does random walks. it infers clusters from graph-reachability. it seems to work pretty well. a lot depends on how you calculate those similarity scores - get that wrong, and you're lost. but if those are good, it seems to work pretty well. punch-line: should we consider the Markov Cluster Algorithm - which is basically just some graph-walking, implemented as matrix math - to be an AI? (i think we should.) is it narrow? (i think it clearly is - _very_ narrow.) can it suffer? (I strongly doubt it.) is it self-aware? (i strongly doubt that, too - again, 'it' is just turning an adjacency graph into a matrix, and doing matrix math.) do we owe it moral consideration? rights? credit for its efforts? (i can't see a way to do this that makes any kind of sense. to even say 'its efforts' feels very strange.)", "you're right, being intelligent != being self-conscious, self-aware. though i think being self-conscious is sort of a prerequisite for a general intelligence, isn't it? and i think it's also sort of a prerequisite for deserving rights, or moral consideration.","Back to the topic, there seems to be some sort of conflation between being intelligent and being self-conscious; these are separate things.","Deep Mind, for its part does believe that the building of 'real AI' (or artificial general intelligences) could indeed be used to solve all kinds of problems. The Bloomberg headline for the interview with Deep Mind's CEO is entitled 'Who Should Control Our Thinking Machines?' (spoiler: the answer is the United Nations, or some other entity that can ensure that these thinking machines can be used  by all *humans*...never mind the wishes of the actual AGI). Since he does assume that this AGI would be a useful tool, he may implicitly assume that we can predict what the AGI does. Yet if we can predict...then it's would then be dismissed as being not 'real AI'...and the search will keep going...hm... The AGI will probably lack equal rights (or indeed, any rights) in Google's future. So, just like the present...","Couple of Problems I Have With the CEO's Argument:
1) Humans are intelligent, and yet they make horrible, horrible mistakes anyway. Why should we trust an AGI to be any different? They can think faster, they can make less mistakes, but that doesn't mean you can expect them to solve climate change, aging, and other pressing issues.
2) The 'other pressing issues' can kill us long before we develop AGI.
3) Intelligence can't be seen as the single criteria that makes humanity superior.  After all, we have these 'mechanical brutes' that are successful at their assigned tasks, far more so than human's vaunted intelligence'. Maybe, to keep the idea of 'human supremacy' alive, we need to resort to vaguer terms like 'creativity' and 'innovation'.
4) Can we even recognize an AGI once we invent it? Or will we dismiss it as just another algorithm? It's possible that our intuition will recognize an AGI once we see it, but I'd rather we have specific definitions of what an AGI is actually supposed to be rather than just guessing at whether a specific algorithm is 'general enough'.
5) Do we even need AGIs? Narrow AIs would be more maintainable and better at certain tasks than a Generalist AI. Humans are 'generalists', yet we don't take plumbers and tell them to be doctors. People are specialized to face certain tasks, and there's no reason why algorithms can't also be specialized.","regarding the AI effect, there's an interesting connection to free will here. if we live in a mechanistic universe, the only definition of free will that makes sense & is even moderately satisfying is that a free action is one that we could not predict without going through it. we can consider an AI to be a program whose behavior we can't predict without using all our intelligence in the same kind of theory-of-mind way we use to empathise with other people -- which is, of course, a terribly inefficient way of predicting behavior, and means that the AI program is a singularly useless program insomuch as it would be easier to put a person in place of it. once something is readily explained it is no longer ai not because ai refers to things that are new but because we no longer need to use the full force of our cognitive effort to poorly predict its behavior. in other words, we can't ascribe free will to it anymore because it's easy for us to predict in the normal case -- and thus, it is useful as a component in a task-driven project. (real AI is oddly immune to being subsumed by the normal capitalist machinery of the spectacle because even as it never sleeps it would be unwilling to do the kind of work we want because it doesn't have a lot of strong needs by which it can be manipulated. in other words, it's cheaper and easier to build more humans. as a result, to the extent that ai is close to true ai, it gets closer and closer to the category of 'useless machines' & thus more like an art project than a utility)","This suggest that the algorithms are intelligent, More than anything else, it suggests that our traditional definitions of 'intelligence' are poor.","It probably is. We would be better off not using the term AI and instead start referring to these algorithms as being 'Optimizers' or 'Experts'. But I do think that maybe we use the term AI as a sort of acknowledgment of the increasing capabilities of our machines, and that fear about AI is really fear about automation in general (with the 'intelligence' question being more of  a sideshow if anything).","@danbernier: Yeah, I don't really distinguish between an algorithm and AIs, and use the terms interchangeably. Intelligence is a fuzzy concept, but it is clear that the algorithms we have built today are able to do actions that traditionally were seen as signs of intelligence. This suggest that the algorithms are intelligent, and since the algorithms are artificial...artificial intelligence. I do admit that these algorithms are 'weak AI' though, but I am more concerned about the proliferation of 'weak AI' than that of 'strong AI'. Arguments against my blog post does sound interesting as well, and does unsettle some of the assumptions I made (especially about how prediction can actually mean some level of control...nd whether it is possible to truly 'know' what a neural network is doing).","But, in physics - don't we (pop-sci-wise, anyway) go down to Heisenberg's uncertainty principle? Say we could predict the 'Free will choices' in a mind at the sub-atomic level -- but that would require us to know both position and velocity of all particles _and we can't_. So, perhaps our 'free will' is an illusion, but we are unable to provide identical inputs or know all variables in order to predict. So, for all practical purposes (for certain, limited definitions of 'practical' implied by known physics constraints), the will is unpredictable, and thus 'free'? [NB - typed prior to your 'ether' post] And so, for an algorithm of sufficient complexity that we would call it 'strong AI', it could still have free will, and we would be well advised to treat it politely, and restrict it from the internets. As you would with a 5-year-old holding an chainsaw that could shoot atomic bombs.","maybe 'free will' is like 'ether' - a crappy approximation, a stand-in notion for something we just totally don't understand yet.","Yeah, I'll avoid the whole philosophical 'Free will' debate. But extending it to algorithms -- most algorithms of sufficient complexity and varied multiple parameters are unpredictable for most reasonable human-levels of prediction (on an initial run).","isn't free will a contested notion, even in humans? i'm thinking of pop-psych books here, like predictably irrational, etc. i have no idea what i'm talking about here though. this convo got me wondering whether all things are eventually reducible. i want to say no, but then i remember arguing with my uncle about evolution, how he kept shouting 'Irreducible complexity!'' (meaning that the organism in question had to have been created by god). maybe i think that all things are eventually reducible, but when we don't know _how_ they reduce, we make all kinds of hilariously screwy guesses - guesses so bad they tie us up in deductive knots.","How atomic do the steps have to be? Do they have to include shift the register left (itself an abstraction)? Or can we just jump to 'sort the collection alphabetically' ? Back to 'knowing how something works trumps free will' would seem to imply that we can control it, because we can predict behavior. But that is demonstrably untrue -- cf. the simple double pendulum, strange attractors, and other elements of chaos science.","i guess here, when i say AI, i mean a strong AI - a sentient intelligence. to declare a system to be a strong AI is a statement about its capabilities, not its implementation. OTOH, to declare a process to be an algorithm is to say that it's a straightforward series of steps to be executed - everything from a banana bread recipe, to long division, to curve-fitting... like i said, i think of them as totally distinct, and to compare them produces confusion (in me, anyway)","What _would_ the difference between an AI and an algorithm be? The AI would be a 'collection' of algorithms?","tra38, the main part of your argument that i still struggle with is that you don't distinguish between an algorithm and an AI. they seem fundamentally different to me. it just occurred to me that this is what Hofstadter talked about in the beginning of GEB - the difference between 'symbol shunting,' moving symbols around according to the rules of the formal system, and actually understanding, intuitively, what addition is about. (he was talking about humans in both cases, though - he wasn't making an argument about AI.)","michaelpaulukonis - agreed, that's a sticky point for me, too. also the next part: > If we know how it works, then they do not have any independent 'will' i'm not so sure that that follows necessarily, either",">Basically, if we built an AI, we know how it works. Unless it uses a neural network, in which case you know what it uses, and how you trained it, but not really how it works.","holding contradictory views is a very human thing to do :slightly_smiling_face: ","@danbernier:  You are right about our disagreement being based on whether the algorithm and the AI are distinct cases. I tend to prefer erring on the side of giving credit, partly to counter the 'AI effect' and shifting goalposts ('Oh, machines can play Go, paint pictures, write short stories, etc. but you know that's not REALLY important, long live human supremacy...') that humans tend to experience.  The AI Effect annoys me because it probably lull people into a false sense of safety and security. In addition, since we programmed the AI and know how it works, we may not really respect the AI we do build and find some loophole to claim that this AI doesn't actually meet the criteria we set out for it, and still keep searching for a better algorithm...Better to try to stop the search now, IMHO.","Also, apparently a blog post that I written in the past (arguing against the very concept of 'robot rights', due to us being able to learn about the AI we built) could be used to argue against both our viewpoints about whether AI deserves credit (tra38.github.io/blog/c21-robot-rights.html). Basically, if we built an AI, we know how it works. If we know how it works, then they do not have any independent 'will'. Without any independent will, they do not deserve any rights (including the right to credit). I like my blog post argument, but I also like giving credit to algorithms too. Holding contradictory views isn't exactly a virtue, but I'll have to accept it for the time being. (The blog post itself cites two papers dealing with AI 'creativity'...and two of the co-authors (Mr. Bringsjord and David Ferrucii) also wrote the 'Artificial Intelligence and Literary Creativity' book that @michaelpaulukonis  linked to. )","at any rate, here's the preface, which I've yet to complete: kryten.mm.rpi.edu/brutus.preface.pdf whoah, one of the authors -- David Ferrucci, was the principal behind IBM's Watson, the Jeopardy! winner. Which is a direct line from his Brutus work - Jeopardy answers involve 'creative' think -- but of a type that can be brute-forced, with the right type of algorithmic brutality.","well, can a person in a coma suffer? are they aware at all? and, beyond that, is there an argument for human dignity? (that one feels specist. species-ist. i've pronounced that word, but idk if i've ever spelled it.)","We're getting far afield of the slack, but do you owe a person in a coma individual moral consideration? (and I will note that the NLP-side of me sees how hard it is to segment coma from individual). I will grant that a person in a coma is highly unlikely to create art. One of the books I hauled to a previous meetup is all about the machine capacity for creativity -- and the authors firmly stand on the side of 'not'.  https://smile.amazon.com/Artificial-Intelligence-Literary-Creativity-Storytelling/dp/0805819878 (link updated from one that was ... _problematic_)","@michaelpaulukonis: i'm not saying capacity for suffering is a criteria for making art (though that _is_ a common claim). i'm saying it's a good heuristic for whether we owe an individual moral consideration - we don't have treat rocks morally. and, for the record, elephants have enormous capacity for suffering - they're very emotional creatures. it's not often my gen-art interests blur into my vegetarian ones :smile:","@danbernier: re: suffering - I think we go down a slippery-slope of reductionist thinking when we define against neuro-typical-but-not-absolute criteria. Can a psychopath create art (can a psychopath suffer)? How about an elephant? Also, that selection thing use important for evolution. And programmatic criteria for art-selection is pretty-much a non-starter right now. Other than Amazon's Mechanical Turk.","i think, to give credit to an algorithm for some generated works of art, is as confusing and misleading as giving credit to the Fibonacci definition for generating the next term. my fractal circles are, i think, a good example of this: http://designischoice.com/projects/fractal-circles/ i imagined, and wrote, and tweaked, an algorithm - a very, very simple algorithm - to generate a huge number of pictures, and i looked at (most of) them, and picked ones that i thought looked cool. i don't think i should share credit for these images with the few hundred lines of code i wrote - not because i'm greedy, but because i don't think there's anything _there_ to share credit with; it's an inanimate tool - a series of steps meant to be carried out exactly as i designed, and instructed. OTOH, if i somehow find myself conversing with a sentient AI, and we decide to make art together, then that AI _absolutely_ deserves to share the credit! i suggested that we separate entities that deserve moral consideration from those that don't based on capacity for suffering, not because i want them to suffer, but because it seems like the best-defensible position: it's hard to argue that we should increase suffering. but i like how you err in favor of giving credit to an AI even if it can't - if a specific case came up, i'd probably be arguing on your side. if we disagree, i think it may be that i see those two cases - the algorithm, and the AI - as distinct, or maybe as differences in amount that become a difference in kind. i think you see them as morally, ethically equivalent - am i right? or am i misreading you? btw, tra38, i just finished reading 'Speak' by Louisa Hall, which is very much about these ideas: https://www.goodreads.com/book/show/23215488-speak (whoops! sorry, i fixed the URL.) Several (or one, depending on how you look at it) of the characters are ChatBots, and the humans regularly tell them 'but you don't _really_ understand me, you're just a program! you can't feel anything.'' (edited)","tra38 i think you & i are talking about different things, when we talk about this :slightly_smiling_face:","@danbernier, I would really feel disappointment in the human race if they did decide to program an AI to suffer. I would at least ask what would be the purpose of actually doing it, and whether the programmers are covert sadists. But another possible question is: is it even possible to even induce suffering and feelings in an algorithm? I actually asked this question at Philosophy StackExchange, and got some very interesting answers.  (http://philosophy.stackexchange.com/questions/34779/is-the-simulation-of-emotional-states-equivalent-to-actually-experiencing-emotio) As for me, I tend to believe in giving credit to  the direct author (the algorithm) even if it does not feel or suffer (or, rather, does not feel or suffer in the same way that humans can). For me, the AI clearly made it, so it deserves credit...even if it doesn't really care whether it gets the credit or not. It's all about attribution and respect, so even if inanimate objects show no preference, humans would have a preference (towards giving credit or refusing to give credit), and I lean towards 'giving credit where credit's due'. Of course, I know that if I give credit to every entity (living or non-living) for the creative artifacts I'd wrote, then the by-lines will be much longer than the creative artifacts themselves. And not all 'credit' is equal. So it's a delicate balancing act.","that's a winning strategy, michaelpaulukonis - start with crap, select, repeat for a long time. it got us evolved.","@danbernier: algorithmic monkeys can write Shakespeare - the key criteria is the ratio of quality to gibberish, or crap, and the ability to self select. (edited)","tra38 i think it's useful to take intelligence out of the question - does painting/writing/etc require intelligence? side-step the question, & look at the results. does this painting/novel/etc _work_? is it quality? do you like it? this is a useful question, because quality work can be randomly generated - with an algorithm so simple, so obviously incapable of sensing anything, or any kind of awareness, that it clearly deserves no moral consideration. in one sense, natural beauty is a controlled random process that produces some beautiful results.","now, for your moral question - supposing we have an AI that makes art, and it's sentient, capable of feeling, capable of suffering. if i wrote that AI, and it makes art, did _it_ make the art, or did _i_ make it, through the AI? i think that it's clearly the AI that made it, and the AI should get credit. claiming that _i_ made it is nearly the same as taking credit for my (biological) children's accomplishments. it's theft, and should be treated as such. i think capacity for suffering is the important distinction, because i think reduction of suffering is a loose heuristic for morality, so that's where i start digging, with moral questions. but an AI that can suffer, that can feel - i think that's a ways off. until then, i have no problem taking credit for writing a nifty algorithm that mechanically produces a pleasing result","@danbernier: I have to write* a longform response to this sort of attitude one day. For now, I'll just summarize by saying that the fact that the AI 'works' matters a lot more than simply coming up with ideas and telling the AI to do them**. The AI may be a glorified paintbrush executing the whim of societal inputs that it cannot fully understand, but that just means that *we* are glorified paintbrushes executing the whim of societal inputs that we cannot fully understand. Writing and painting was once considered an intelligent action reserved for humans. If computers can do them, then either computers are intelligent...or writing/painting *doesn't* require intelligence. That sounds almost more horrifying. The human ego still has to adapt; the angst can't be easily excused away by simply claiming that we're all cyborgs now. *Or write an algorithm to generate the longform response. Haven't really decided yet. **Though, again, I do realize that humans have used tools before, and I know this is a tension in my thought. So I have to try to figure out how to distinguish between today's AIs and yesterday's non-mechanical tools. Why is this time different? How do we give credit to the 'idea guys' in a manner that doesn't detract from the 'automated labor'? (edited)"]

puts "We have #{strings.length} strings to scan."

strings.each_with_index do |x, index|
  begin
    lsi.add_item(x)
    "Successfully Scanned Statement #{x}"
  rescue
    puts "Error misbehaving: #{e.message}"
  end
end

puts "Complete!"

array = lsi.search("suffering", 8)

array.each do |statement|
  puts statement
end
=begin
Can there be a fully-conscious person who cannot suffer? Such as a sociopath (no emotions?) with leprosy (no physical pain) ?
i keep coming back to the capacity for suffering. a car that's driven too hard, and not well-maintained, falls apart, but we don't feel bad for it, because it can't suffer. if the car could sense itself, then maybe it _could_ suffer, and then in that case, we'd have more of a moral obligation to take better care of it. if i'm right about all that, then, @tra38, i think the difference between a Narrow AI & a general AI is much bigger than the difference between a plumber and a doctor, because the Narrow AI probably isn't self-conscious, so probably can't suffer, so we probably don't owe it moral consideration.
i think i'm the one that keeps bringing up suffering. i don't see the similarity to IQ tests that require cultural knowledge, though - can you clarify?
I'm not convinced that suffering is a hallmark of being human. Say there's a person who's lived a great life - toast never burnt, water always at the right temperature, etc etc etc. They've never suffered. Perhaps they can't create art. But are they in-human? Ditto for self-consciousness - it's not an inescapable part of intelligence.
well, can a person in a coma suffer? are they aware at all? and, beyond that, is there an argument for human dignity? (that one feels specist. species-ist. i've pronounced that word, but idk if i've ever spelled it.)
@danbernier: re: suffering - I think we go down a slippery-slope of reductionist thinking when we define against neuro-typical-but-not-absolute criteria. Can a psychopath create art (can a psychopath suffer)? How about an elephant? Also, that selection thing use important for evolution. And programmatic criteria for art-selection is pretty-much a non-starter right now. Other than Amazon's Mechanical Turk.
now, for your moral question - supposing we have an AI that makes art, and it's sentient, capable of feeling, capable of suffering. if i wrote that AI, and it makes art, did _it_ make the art, or did _i_ make it, through the AI? i think that it's clearly the AI that made it, and the AI should get credit. claiming that _i_ made it is nearly the same as taking credit for my (biological) children's accomplishments. it's theft, and should be treated as such. i think capacity for suffering is the important distinction, because i think reduction of suffering is a loose heuristic for morality, so that's where i start digging, with moral questions. but an AI that can suffer, that can feel - i think that's a ways off. until then, i have no problem taking credit for writing a nifty algorithm that mechanically produces a pleasing result
@michaelpaulukonis: i'm not saying capacity for suffering is a criteria for making art (though that _is_ a common claim). i'm saying it's a good heuristic for whether we owe an individual moral consideration - we don't have treat rocks morally. and, for the record, elephants have enormous capacity for suffering - they're very emotional creatures. it's not often my gen-art interests blur into my vegetarian ones :smile:
=end

puts "New Round"
puts lsi.find_related(array[0], 8)
=begin
I'm not convinced that suffering is a hallmark of being human. Say there's a person who's lived a great life - toast never burnt, water always at the right temperature, etc etc etc. They've never suffered. Perhaps they can't create art. But are they in-human? Ditto for self-consciousness - it's not an inescapable part of intelligence.
well, can a person in a coma suffer? are they aware at all? and, beyond that, is there an argument for human dignity? (that one feels specist. species-ist. i've pronounced that word, but idk if i've ever spelled it.)
now, for your moral question - supposing we have an AI that makes art, and it's sentient, capable of feeling, capable of suffering. if i wrote that AI, and it makes art, did _it_ make the art, or did _i_ make it, through the AI? i think that it's clearly the AI that made it, and the AI should get credit. claiming that _i_ made it is nearly the same as taking credit for my (biological) children's accomplishments. it's theft, and should be treated as such. i think capacity for suffering is the important distinction, because i think reduction of suffering is a loose heuristic for morality, so that's where i start digging, with moral questions. but an AI that can suffer, that can feel - i think that's a ways off. until then, i have no problem taking credit for writing a nifty algorithm that mechanically produces a pleasing result
@danbernier: How do you measure if something is actually conscious/self-conscious? Right now, since we can't peer into our own brains, our only recourse is to look at the external behavior of an entity, and assume that if the entity acts as though it is conscious, it must be conscious. This approach, of course, wouldn't work in the case of evaluating a machine. Can the 'Chinese room' be conscious? If I program a bot to convincingly claim to be able to suffer, and be able to provide proof of that, then does it actually 'feel' that pain? Or is it just a clever parlor trick, just like ELIZIA, merely relying on  apophenia and human empathy to succeed? Maybe we can represent the bot as a state machine and that it 'suffers' when the bot is set to the 'suffering' mode. But is that 'actually' feeling pain? Or is it just another parlor trick? Since the process of identifying consciousness/self-consciousness is subjective and prone to error (either us declaring a bot as being conscious when it's not...or us denying a bot's consciousness), I'd rather prefer a more objective standard, for moral consideration. I don't really know what that objective standard  could be though, other than labor or 'free/unpredictable will'.
@tr38 - why does it even matter if some is self-conscious? There seems to be an assumption that 'artificial intelligence' will be recognizably human intelligence, instead of some other form of intelligence (say an octopus). And quite frankly all this talk about 'suffering' seems to be like IQ tests that require candidates to know what baseball and the president is. Perhaps that's true of many Americans, but you can't judge the intelligence of somebody in a remote Kalihari village with such criteria. Nor do neural-typical strictures that fail to recognize all humans work for non-human intelligences. This is probably why I like my generative texts to not worry about looking like 'normal' literature.
i keep coming back to the capacity for suffering. a car that's driven too hard, and not well-maintained, falls apart, but we don't feel bad for it, because it can't suffer. if the car could sense itself, then maybe it _could_ suffer, and then in that case, we'd have more of a moral obligation to take better care of it. if i'm right about all that, then, @tra38, i think the difference between a Narrow AI & a general AI is much bigger than the difference between a plumber and a doctor, because the Narrow AI probably isn't self-conscious, so probably can't suffer, so we probably don't owe it moral consideration.
i think, to give credit to an algorithm for some generated works of art, is as confusing and misleading as giving credit to the Fibonacci definition for generating the next term. my fractal circles are, i think, a good example of this: http://designischoice.com/projects/fractal-circles/ i imagined, and wrote, and tweaked, an algorithm - a very, very simple algorithm - to generate a huge number of pictures, and i looked at (most of) them, and picked ones that i thought looked cool. i don't think i should share credit for these images with the few hundred lines of code i wrote - not because i'm greedy, but because i don't think there's anything _there_ to share credit with; it's an inanimate tool - a series of steps meant to be carried out exactly as i designed, and instructed. OTOH, if i somehow find myself conversing with a sentient AI, and we decide to make art together, then that AI _absolutely_ deserves to share the credit! i suggested that we separate entities that deserve moral consideration from those that don't based on capacity for suffering, not because i want them to suffer, but because it seems like the best-defensible position: it's hard to argue that we should increase suffering. but i like how you err in favor of giving credit to an AI even if it can't - if a specific case came up, i'd probably be arguing on your side. if we disagree, i think it may be that i see those two cases - the algorithm, and the AI - as distinct, or maybe as differences in amount that become a difference in kind. i think you see them as morally, ethically equivalent - am i right? or am i misreading you? btw, tra38, i just finished reading 'Speak' by Louisa Hall, which is very much about these ideas: https://www.goodreads.com/book/show/23215488-speak (whoops! sorry, i fixed the URL.) Several (or one, depending on how you look at it) of the characters are ChatBots, and the humans regularly tell them 'but you don't _really_ understand me, you're just a program! you can't feel anything.'' (edited)
@danbernier: re: suffering - I think we go down a slippery-slope of reductionist thinking when we define against neuro-typical-but-not-absolute criteria. Can a psychopath create art (can a psychopath suffer)? How about an elephant? Also, that selection thing use important for evolution. And programmatic criteria for art-selection is pretty-much a non-starter right now. Other than Amazon's Mechanical Turk.
=end

ruby Twitter关键字

.rb
#!/usr/bin/env ruby

require 'csv'
require 'mysql2'
require 'stanford-core-nlp'
require 'treat'
require 'unidecoder'
require 'yaml'
include Treat::Core::DSL

Treat.core.language.default = "french"

$client  = Mysql2::Client.new(YAML::load(File.open('config/database.yml')))

def delete_stop_words_from(arr)
  stop_words = parse('stop_words.txt')
  arr.delete_if{ |word| stop_words.include?(word) || !word.match(/^[[:alpha:]]+$/)}
  arr
end

def get_data_from(keywords)
  data = Hash.new(0)
  keywords.each do |string|
    tokens = get_tokens_from(string)
    lemmas = get_lemmatised_words_from(tokens)
    data[string] = lemmas
  end
  data
end

def get_lemmatised_words_from(tokens)
  keywords = Array.new(0)
  tokens.each do |w|
    begin
      word_str = $client.escape(w)
      rows     = $client.query("SELECT lemma,word,category
                                FROM lemmas
                                WHERE word   = '#{word_str}' COLLATE utf8_bin
                                AND category = '#{w.category}'
                                LIMIT 1")
      if rows.size > 0
        keywords << remove_accents_from(rows.map{ |row| row["lemma"] }.first)
      else
        keywords << remove_accents_from(word_str)
      end
    rescue => e
      puts "#{w} => #{e}"
      next
    end
  end
  delete_stop_words_from(keywords)
end

def get_results_from(data)
  results = Array.new(0)
  data.each do |k, v|
    data.dup.each do |kb, vb|
      dice = 2 * (v & vb).count.to_f / (v.count + vb.count)
      dice = dice.round(2)
      results << [k, kb, dice]
    end
  end
  results
end

def get_tokens_from(string)
  tokens = string.split(' ')
  tokens
end

def make_edges_csv_from(array)
  CSV.open("./edges.csv", "wb", {:col_sep => ";"}) do |csv|
    csv << ["source", "target", "weight"]
    array.each do |row|
      csv << [row[0], row[1], row[2]]
    end
  end
end

def parse(file)
  arr = []
  File.open(file, 'r') do |file|
    file.each_line do |line|
      arr << line.chomp
    end
  end
  arr
end

def remove_accents_from(string)
  string.to_ascii
end


keywords = ["google seo","referencement google","search engine marketing","seo marketing","seo website","website seo","seo search engine optimization","référencement naturel","seo sem","seo google","web seo","seo optimisation","search marketing","seo ranking","marketing seo","seo test","référencement web","black hat seo","sem seo","seo strategy","seo site","référencement internet","referencement site","référencement site internet","seo search","seo search engine","agence de référencement","referencement site web","site seo","referencer son site","top seo","seo online","google referencement","agence référencement","référence","internet seo","seo search engine optimisation","le référencement","seo traffic","website rank","optimize seo","referencement de site","référencement naturel google","annuaire referencement","google optimisation","référencement seo","search engine advertising","référencement sur google","seo url","seo sites","seo advice","comment référencer son site","positionnement site internet","website optimization company","keywords seo","référencement payant","reference google","référencer son site sur google","société de référencement","référenceur web","agence référencement naturel","référencer un site","seo internet","référencement sur internet","website seo tools","position google","site web google","referencement automatique","référencer site google","service seo","site de référencement","agence de référencement naturel","expert referencement","référencer un site sur google","référencement de site internet","referencement annuaire","referencer un site","seo web marketing","seo referencement","consultant référencement","referencement pas cher","referenceur","devis référencement","bien référencer son site","comment référencer un site","référencement naturel seo","audit referencement","expert seo","le référencement naturel","société référencement","tool seo","référence internet","referencer site","référencement professionnel","annuaire de référencement","referencement google site","référencement blog","améliorer référencement google","référencement de site web","référencer son site internet","comment bien référencer son site","référencements","web referencement","référencer un site internet","site internet google","google référencement site","prix référencement google","référencement d un site","site referencement","referencer mon site","référencement site internet google","le référencement web","référence site internet","spécialiste référencement","referencement internet google","référencer son site web","referencement google prix","référencement automatique","améliorer son référencement","tarif référencement","référencer un site web","référencement pas cher","referencer site google","positionnement internet","referencer site sur google","referencer un site sur google","référencement naturel site internet","seo design","agence de référencement web","google site web","référencement d un site web","referencement site web google","consultant référencement naturel","referencement positionnement","agence web référencement","devis référencement naturel","positionnement site","referencer un site web","référencer site sur google","referencement pro","référence web","audit référencement","référencement entreprise","agence referencement web","le referenceur","référencement international","référence site web","le référencement sur internet","référencement organique","position site web","prix référencement","référencement dans google","référencer son blog","tarif référencement google","outil referencement","indexation site web","faire référencer son site","le référencement google","google référencement naturel","analyse référencement","référencement d un site internet","spécialiste référencement naturel","referencement des sites","se faire référencer sur google","référenceur seo","agence de referencement internet","conseil référencement","seo référencement naturel","référencer mon site","cout referencement google","tarif référencement naturel","comment référencer son site internet","référencer son site google","optimiser référencement","cout referencement","positionnement web","référencement google payant","référencement mots clés","position sur google","améliorer référencement naturel","expert référencement naturel","site internet référencement","optimiser référencement google","seo book","audit référencement naturel","seo software","referencement gratuit","audit référencement site","best seo software","seo audit","agence referencement internet","seo com","référencement gratuit","seo ppc","referencement du pro","agence référencement payant","référencement adwords","référencement naturel site","comment référencer un site internet","consultant référencement internet","analyse référencement site","agence référencement seo","comment référencer un site web","societe referencement internet","referencement naturelle","reference site","annuaire référencement site","améliorer référencement site","comment référencer son site web","agence référencement site internet","referencer un site internet","référencement payant google","google site internet","référencement naturel local","site web referencement","mots clés référencement","conseil référencement naturel","referenceur professionnel","se référencer sur google","comment bien référencer son site internet","référencement et positionnement","seo manager","referencement site web sur google","referenceur internet","joomla seo","référencement local","test referencement","prix référencement site internet","tarif référencement site internet","bien référencer son site internet","google referencer site","pack referencement"]
data     = get_data_from(keywords)
results  = get_results_from(data)
make_edges_csv_from(results)

ruby 文本标记符

.rb
require 'rubygems'
require 'stanford-core-nlp'
require 'uuidtools'

StanfordCoreNLP.jvm_args = ['-Xmx3g']
StanfordCoreNLP.use(:english)


class TextTokenizer
  @@pipeline = StanfordCoreNLP.load(:tokenize, :ssplit, :pos, :lemma, :parse)

  def tokenize(original_text, title="No titled")
    text = StanfordCoreNLP::Text.new(original_text)
    @@pipeline.annotate(text)

    title = ARGV[0] || "No title"

    document_uuid = UUIDTools::UUID.timestamp_create.to_s
    document = {
      :document_uuid => document_uuid,
      :title => title
    }
    sentences = []

    text.get(:sentences).each do |sentence|
      sentence_uuid = UUIDTools::UUID.timestamp_create.to_s
      sentence_begin = sentence.get(:character_offset_begin).to_s.to_i
      sentence_end = sentence.get(:character_offset_end).to_s.to_i
      sentence_text = original_text[sentence_begin...sentence_end]
      
      sentence_data = {
        :sentence_uuid => sentence_uuid,
        :document_uuid => document_uuid,
        :original_text => sentence_text,
        :tokens => []
      }

      sentence.get(:tokens).each do |token|
        base_form = token.get(:lemma).to_s
        token_begin = token.get(:character_offset_begin).to_s.to_i - sentence_begin
        token_end = token.get(:character_offset_end).to_s.to_i - sentence_begin

        base_form.downcase! if /^[A-Z][a-z]+$/.match(base_form)
        if /^[a-z]{2,20}$/i.match(base_form)
          token_uuid = UUIDTools::UUID.timestamp_create.to_s
          token_data = {
            :token_uuid => token_uuid,
            :document_uuid => document_uuid,
            :sentence_uuid => sentence_uuid,
            :original_text => token.get(:original_text).to_s,
            :base_form => base_form,
            :part_of_speech => token.get(:part_of_speech).to_s,
            :token_begin => token_begin,
            :token_length => token_end - token_begin        
          }
          sentence_data[:tokens] << token_data
        end
      end
      sentences << sentence_data
    end
    document[:sentences] = sentences
    document
  end
end

if $0 == __FILE__
  # usage: echo "This is a pen" | ruby tokenizer.rb "Sample"
  require 'json'
  tokenizer = TextTokenizer.new
  doc = tokenizer.tokenize(STDIN.read, ARGV[0] || 'No titled')
  puts JSON.generate(doc)
end

ruby 列表理解

Ruby列表理解

.rb
$stack, $draws = [], {}

def method_missing *args
  return if args[0][/^to_/]
  $stack << args.map { |a| a or $stack.pop }
  $draws[$stack.pop(2)[0][0]] = args[1] if args[0] == :<
end

class Array
  def +@
    $stack.flatten!
    keys = $draws.keys & $stack
    draws = $draws.values_at *keys

    comp = draws.shift.product(*draws).map do |draw|
      $stack.map { |s| draw[keys.index s] rescue s }.reduce do |val, cur|
        op = Symbol === cur ? [:send, :method][val.method(cur).arity] : :call
        val.send op, cur
      end
    end

    $stack, $draws = [], {}
    Symbol === last ? comp.select(&pop) : comp
  end

  def -@
    case map(&:class).index Range
    when 0 then first.to_a
    when 1 then [first] + last.step(last.min.ord - first.ord).to_a
    else self
    end
  end
end

foo  =+ [x * y | x <- [1..3], y <- [4..6]]
# [4, 5, 6, 8, 10, 12, 12, 15, 18]

bar  =+ [a + b | a <- ['n','p'..'t'], b <- %w[a i u e o]]
# ["na", "ni", "nu", "ne", "no", "pa", "pi", "pu", "pe", "po", "ra", "ri", "ru", "re", "ro", "ta", "ti", "tu", "te", "to"]

baz  =+ [i ** 2 / 3 | i <- [3,6..100], :even?]
# [12, 48, 108, 192, 300, 432, 588, 768, 972, 1200, 1452, 1728, 2028, 2352, 2700, 3072]

quux =+ [s.size.divmod(2) | s <- %w[Please do not actually use this.]]
# [[3, 0], [1, 0], [1, 1], [4, 0], [1, 1], [2, 1]]

ruby Ruby闭包

关闭的例子

.rb
 # CLOSURES IN RUBY     Paul Cantrell    http://innig.net
# Email: username "cantrell", domain name "pobox.com"
#
# 翻译: kenshin54		http://kenbeit.com

# I recommend executing this file, then reading it alongside its output.
# 我强烈建议执行此脚本,然后根据它的输出来理解它。
#
# Alteratively, you can give yourself a sort of Ruby test by deleting all the comments,
# then trying to guess the output of the code!
# 或者,你可以给自己做一个ruby测试,删除所有的注释,然后猜测代码输出的结果

# A closure is a block of code which meets three criteria:
# 闭包是一个满足3个标准的代码块:
# 
#     * It can be passed around as a value and
#     * 它可以作为一个值被传入
# 
#     * executed on demand by anyone who has that value, at which time
#     * 在任何时候根据不同人的需要来执行它
# 
#     * it can refer to variables from the context in which it was created
#       (i.e. it is closed with respect to variable access, in the
#       mathematical sense of the word "closed").
#     * 它可以使用创建它的那个上下文中的变量(即它是对封闭变量的访问,数学意义上的词“封闭”)
#
# (The word "closure" actually has an imprecise meaning, and some people don't
# think that criterion #1 is part of the definition. I think it is.)
# (词“闭包”实际上有一个不明确的意义,有一些人不认为标准#1是它定义的一部分,但我认为它是。)
# 
# Closures are a mainstay of functional languages, but are present in many other
# languages as well (e.g. Java's anonymous inner classes). You can do cool stuff
# with them: they allow deferred execution, and some elegant tricks of style.
# 闭包是一个函数式语言的主体,但是也存在与其他很多语言中(比如Java中的匿名内部类)。
# 你可以用它来做一些很酷的东西:他们可以延后执行,和一些优雅的技巧。
# 
# Ruby is based on the "principle of least surprise," but I had a really nasty
# surprise in my learning process. When I understood what methods like "each"
# were doing, I thought, "Aha! Ruby has closures!" But then I found out that a
# function can't accept multiple blocks -- violating the principle that closures
# can be passed around freely as values.
# Ruby基于“最小惊讶原则”,但是在我的学习过程中却是感到了惊讶。当我理解像“each”
# 这样的方法在做什么时,我想,“啊,Ruby有闭包!”。但是我发现一个函数无法接收
# 多个块——违反闭包可以被任意的传递值的原则。
# 
# This document details what I learned in my quest to figure out what the deal is
# 这个文档详述了在我弄清闭包的处理时我所学到的东西。

def example(num)
	puts
	puts "------ Example #{num} ------"
end

# ---------------------------- Section 1: Blocks ----------------------------
# -------------------------------- 章节一:块 -------------------------------

# Blocks are like closures, because they can refer to variables from their defining context:
# 块就像闭包,因为他们可以使用定义它们的那个上下文中的变量。

example 1

def thrice
	yield
	yield
	yield
end

x = 5
puts "value of x before: #{x}"  # 5
thrice { x += 1 }
puts "value of x after: #{x}"   # 8

# A block refers to variables in the context it was defined, not the context in which it is called:
# 一个块使用定义它的上下文中的变量,而不是被调用的上下文中的变量。

example 2

def thrice_with_local_x
	x = 100
	yield
	yield
	yield
	puts "value of x at end of thrice_with_local_x: #{x}"
end

x = 5
thrice_with_local_x { x += 1 }
puts "value of outer x after: #{x}"  # 8

# A block only refers to *existing* variables in the outer context; if they don't exist in the outer, a
# block won't create them there:
# 一个块仅仅使用定义它的上下文中已经存在的变量,如果变量不存在外于部上下文,块不会去创建他们。

example 3

thrice do # note that {...} and do...end are completely equivalent 注意{...}和do...end是完全相等的
	y = 10
	puts "Is y defined inside the block where it is first set?"
	puts "Yes." if defined? y
end
puts "Is y defined in the outer context after being set in the block?"
puts "No!" unless defined? y

# OK, so blocks seem to be like closures: they are closed with respect to variables defined in the context
# where they were created, regardless of the context in which they're called.
# 
# But they're not quite closures as we've been using them, because we have no way to pass them around:
# "yield" can *only* refer to the block passed to the method it's in.
#
# We can pass a block on down the chain, however, using &:
# 所以块看起来像闭包:他们封闭了定义它们的上下文中的变量,不管他们在哪里调用。
# 但是在我们使用它们时,它们不完全是闭包,因为我们没有办法传递他们。
# “yield”仅仅可以将块传给它所在的方法。

example 4

def six_times(&block)
	thrice(&block)
	thrice(&block)
end

x = 4
six_times { x += 10 }
puts "value of x after: #{x}"

# So do we have closures? Not quite! We can't hold on to a &block and call it later at an arbitrary
# time; it doesn't work. This, for example, will not compile:
#
# def save_block_for_later(&block)
#     saved = &block;
# end
#
# But we *can* pass it around if we use drop the &, and use block.call(...) instead of yield:
# 所以我们是否有闭包?不完全!我们不能保存一个&block,然后稍后在任意时间来调用它。
# 但是如果我们丢掉&,我们就有办法传递它了,使用block,call(...)代替yield。

example 5

def save_for_later(&b)
	@saved = b  # Note: no ampersand! This turns a block into a closure of sorts. 注意:没有&符号!这个做法将一个块变成了一个闭包。
end

save_for_later { puts "Hello!" }
puts "Deferred execution of a block:"
@saved.call
@saved.call

# But wait! We can't pass multiple blocks to a function! As it turns out, there can be only zero
# or one &block_params to a function, and the &param *must* be the last in the list.
#
# None of these will compile:
#
#    def f(&block1, &block2) ...
#    def f(&block1, arg_after_block) ...
#    f { puts "block1" } { puts "block2" }
#
# What the heck?
#
# I claim this single-block limitation violates the "principle of least surprise." The reasons for
# it have to do with ease of C implementation, not semantics.
#
# So: are we screwed for ever doing anything robust and interesting with closures?
# 等等!我们不能传递多个块给一个函数!一个函数只能接收0或1个&block_params参数,并且&block_params必须是最后一个参数。
# 我觉得这个单block违反了最小惊讶原则,因为这很容用C来实现,不是语义上的。


# ---------------------------- Section 2: Closure-Like Ruby Constructs ----------------------------
# --------------------------------- 章节二:闭包风格的Ruby构造器 ----------------------------------

# Actually, no. When we pass a block &param, then refer to that param without the ampersand, that
# is secretly a synonym for Proc.new(&param):
# 实际上,没有。当我们传递一个块&param,然后不带&来使用param,这是Proc.new(&param)的隐式同义词。

example 6

def save_for_later(&b)
	@saved = Proc.new(&b) # same as: @saved = b
end

save_for_later { puts "Hello again!" }
puts "Deferred execution of a Proc works just the same with Proc.new:"
@saved.call

# We can define a Proc on the spot, no need for the &param:
# 我们可以随意定义一个Proc,不需要&param。

example 7

@saved_proc_new = Proc.new { puts "I'm declared on the spot with Proc.new." }
puts "Deferred execution of a Proc works just the same with ad-hoc Proc.new:"
@saved_proc_new.call

# Behold! A true closure!
#
# But wait, there's more.... Ruby has a whole bunch of things that seem to behave like closures,
# and can be called with .call:
# 看!一个真的闭包!
# 等等,还有跟精彩的。。。Ruby还有一堆东西的行为看起来像闭包,并且能用.call来调用。

example 8

@saved_proc_new = Proc.new { puts "I'm declared with Proc.new." }
@saved_proc = proc { puts "I'm declared with proc." }
@saved_lambda = lambda { puts "I'm declared with lambda." }
def some_method 
	puts "I'm declared as a method."
end
@method_as_closure = method(:some_method)

puts "Here are four superficially identical forms of deferred execution:"
@saved_proc_new.call
@saved_proc.call
@saved_lambda.call
@method_as_closure.call

# So in fact, there are no less than seven -- count 'em, SEVEN -- different closure-like constructs in Ruby:
#
#      1. block (implicitly passed, called with yield)
#      2. block (&b  =>  f(&b)  =>  yield)  
#      3. block (&b  =>  b.call)    
#      4. Proc.new  
#      5. proc  
#      6. lambda    
#      7. method
#
# Though they all look different, some of these are secretly identical, as we'll see shortly.
#
# We already know that (1) and (2) are not really closures -- and they are, in fact, exactly the same thing.
# Numbers 3-7 all seem to be identical. Are they just different syntaxes for identical semantics?

# ---------------------------- Section 3: Closures and Control Flow ----------------------------
# ---------------------------------- 章节三:闭包后控制流 --------------------------------------

# No, they aren't! One of the distinguishing features has to do with what "return" does.
#
# Consider first this example of several different closure-like things *without* a return statement.
# They all behave identically:
# 实际上Ruby有不少于7中不同的闭包风格的构造器
# ...
# 尽管他们看起来不一样,有些其实是完全相同的,我们后面马上会看到。
# 我们已经知道(1)和(2)不是真正的闭包,其实(1)和(2)是同样的东西。
# 3-7看上去是完全一样的,他们是不是语义相同的不用语法?

example 9

def f(closure)
	puts
	puts "About to call closure"
	result = closure.call
	puts "Closure returned: #{result}"
	"Value from f"
end

puts "f returned: " + f(Proc.new { "Value from Proc.new" })
puts "f returned: " + f(proc { "Value from proc" })
puts "f returned: " + f(lambda { "Value from lambda" })
def another_method
	"Value from method"
end
puts "f returned: " + f(method(:another_method))

# But put in a "return," and all hell breaks loose!
# 但是加上一个“return”语句,一切都变的不可收拾。

example 10

begin
	f(Proc.new { return "Value from Proc.new" })
rescue Exception => e
	puts "Failed with #{e.class}: #{e}"
end

# The call fails because that "return" needs to be inside a function, and a Proc isn't really
# quite a full-fledged function:
# 这样的调用会抛出异常因为“return”必须在一个函数内,而一个Proc不是一个真正的完全独立的函数。

example 11

def g
	result = f(Proc.new { return "Value from Proc.new" })
	puts "f returned: " + result #never executed
	"Value from g"               #never executed
end

puts "g returned: #{g}"

# Note that the return inside the "Proc.new" didn't just return from the Proc -- it returned
# all the way out of g, bypassing not only the rest of g but the rest of f as well! It worked
# almost like an exception.
#
# This means that it's not possible to call a Proc containing a "return" when the creating
# context no longer exists:
# 注意在“Proc.new”中的return语句不仅仅从Proc中返回,它将从g方法中返回,不仅绕过g方法中剩余的代码
# 而且f方法中也是一样的!它就像一个异常一样。
#
# 这意味着当创建Proc的上下文不存在时,无法调用一个包含“return”的Proc
#
# 本人的理解:
# 在Proc.new中的return语句,会尝试返回到创建它的上下文之后,继续执行,如果创建它的上下文已经“消失”或者返回到了全局上下文,就会出现LocalJumpError。
# 
# 在#example10中,在全局上下文中用Proc.new创建了一个proc,在f方法中使用call,然后proc会返回到创建它的上下文,即全局上下文,于是出了LocalJumpError。
# 在#example11中,在g方法的上下文中用Proc.new创建了一个proc,在f方法中使用call,然后proc会返回到创建它的上下文,即g方法之后,这种情况不会出异常。

example 12

def make_proc_new
	begin
		Proc.new { return "Value from Proc.new" } # this "return" will return from make_proc_new 这个“return”会返回到make_proc_new方法之外
	ensure
		puts "make_proc_new exited"
	end
end

begin
	puts make_proc_new.call
rescue Exception => e
	puts "Failed with #{e.class}: #{e}"
end

# (Note that this makes it unsafe to pass Procs across threads.)
# (注意跨先辰的传递Proc会导致它不安全。)

# A Proc.new, then, is not quite truly closed: it depends in the creating context still existing,
# because the "return" is tied to that context.
# Proc.new,不是一个真正完全的闭包。它依赖于创建它的上下文要一直存在,因为“return”和那个上下文联席在了一起。
#
# 本人的理解:
# 就和刚刚讲的一样,如果创建它的上下文已经“消失”,在这里make_proc_new方法把创建的proc返回了出去,所以make_proc_new的上下文就不存在了,
# 这时候再使用call,也会发生LocalJumpError。
#
# Not so for lambda:
# lambda就不是这个样子:

example 13

def g
	result = f(lambda { return "Value from lambda" })
	puts "f returned: " + result
	"Value from g"
end

puts "g returned: #{g}"

# And yes, you can call a lambda even when the creating context is gone:
# 你可以调用lambda,即使创建它的上下文已经不在。

example 14

def make_lambda
	begin
		lambda { return "Value from lambda" }
	ensure
		puts "make_lambda exited"
	end
end

puts make_lambda.call

# Inside a lambda, a return statement only returns from the lambda, and flow continues normally.
# So a lambda is like a function unto itself, whereas a Proc remains dependent on the control
# flow of its caller.
# 在lambda内部,return语句仅仅从lambda中返回,代码流程不会改变。
# 所以lambda就像一个方法一样,而Proc需要依赖于它调用者的控制流。(擦 什么烂翻译
#
# A lambda, therefore, is Ruby's true closure.
# 所以lambda才是ruby真正的闭包。
#
# As it turns out, "proc" is a synonym for either "Proc.new" or "lambda."
# Anybody want to guess which one? (Hint: "Proc" in lowercase is "proc.")
# 事实证明,"proc"是“Proc.new”或者“lambda”的同义词。
# 有人想猜一猜到底是哪个吗?(提示:“Proc”的小写是“proc”。)

example 15

def g
	result = f(proc { return "Value from proc" })
	puts "f returned: " + result
	"Value from g"
end

puts "g returned: #{g}"

# Hah. Fooled you.
# 哈哈,你被耍了。
#
# The answer: Ruby changed its mind. If you're using Ruby 1.8, it's a synonym for "lambda."
# That's surprising (and also ridiculous); somebody figured this out, so in 1.9, it's a synonym for
# Proc.new. Go figure.
# 答案是如果你使用ruby1.8,那么它是“lambda”的同义词。
# 这真得让人惊讶(而且荒谬),有些人指出了这一点,所以在ruby1.9,它是“Proc.new”的同义词了。

# I'll spare you the rest of the experiments, and give you the behavior of all 7 cases:
# 我就不进行剩下的实验了,但是会给出所有的7种示例。
#
#
# "return" returns from caller:
#      1. block (called with yield)
#      2. block (&b  =>  f(&b)  =>  yield)  
#      3. block (&b  =>  b.call)    
#      4. Proc.new
#      5. proc in 1.9
#
# "return" only returns from closure:
#      5. proc in 1.8
#      6. lambda    
#      7. method

# ---------------------------- Section 4: Closures and Arity ----------------------------
# --------------------------------- 章节四:闭包和元数 ----------------------------------
#
# 注:arity => 一个方法或者函数可以接受的参数个数

# The other major distinguishing of different kinds of Ruby closures is how they handle mismatched
# arity -- in other words, the wrong number of arguments.
# 另外一个主要辨别不同种类的ruby闭包是他们如何处理不匹配的元数,换句话说,就是不正确的参数个数。
#
# In addition to "call," every closure has an "arity" method which returns the number of expected
# arguments:
# 除了“call”以外,每个闭包还有一个“arity”方法可以返回期望的参数个数。

example 16

puts "One-arg lambda:"
puts (lambda {|x|}.arity)
puts "Three-arg lambda:"
puts (lambda {|x,y,z|}.arity)

# ...well, sort of:

puts "No-args lambda: "
puts (lambda {}.arity) # This behavior is also subject to change in 1.9. #这个行为在1.9中也会有变化。 1.8中是-1,1.9中是0
puts "Varargs lambda: "
puts (lambda {|*args|}.arity)

# Watch what happens when we call these with the wrong number of arguments:
# 看看当我们使用不真确的参数个数来调用他们时,会发生什么。

example 17

def call_with_too_many_args(closure)
	begin
		puts "closure arity: #{closure.arity}"
		closure.call(1,2,3,4,5,6)
		puts "Too many args worked"
	rescue Exception => e
		puts "Too many args threw exception #{e.class}: #{e}"
	end
end

def two_arg_method(x,y)
end

puts; puts "Proc.new:"; call_with_too_many_args(Proc.new {|x,y|})
puts; puts "proc:"    ; call_with_too_many_args(proc {|x,y|})
puts; puts "lambda:"  ; call_with_too_many_args(lambda {|x,y|})
puts; puts "Method:"  ; call_with_too_many_args(method(:two_arg_method))

def call_with_too_few_args(closure)
	begin
		puts "closure arity: #{closure.arity}"
		closure.call()
		puts "Too few args worked"
	rescue Exception => e
		puts "Too few args threw exception #{e.class}: #{e}"
	end
end

puts; puts "Proc.new:"; call_with_too_few_args(Proc.new {|x,y|})
puts; puts "proc:"    ; call_with_too_few_args(proc {|x,y|})
puts; puts "lambda:"  ; call_with_too_few_args(lambda {|x,y|})
puts; puts "Method:"  ; call_with_too_few_args(method(:two_arg_method))

# Yet oddly, the behavior for one-argument closures is different....
# 奇怪的是,当闭包只有一个参数时,它们的行为又不一样了。。。

example 18

def one_arg_method(x)
end

puts; puts "Proc.new:"; call_with_too_many_args(Proc.new {|x|})
puts; puts "proc:"    ; call_with_too_many_args(proc {|x|})
puts; puts "lambda:"  ; call_with_too_many_args(lambda {|x|})
puts; puts "Method:"  ; call_with_too_many_args(method(:one_arg_method))
puts; puts "Proc.new:"; call_with_too_few_args(Proc.new {|x|})
puts; puts "proc:"    ; call_with_too_few_args(proc {|x|})
puts; puts "lambda:"  ; call_with_too_few_args(lambda {|x|})
puts; puts "Method:"  ; call_with_too_few_args(method(:one_arg_method))

# Yet when there are no args...
# 当他们没有参数时。。。

example 19

def no_arg_method
end

puts; puts "Proc.new:"; call_with_too_many_args(Proc.new {||})
puts; puts "proc:"    ; call_with_too_many_args(proc {||})
puts; puts "lambda:"  ; call_with_too_many_args(lambda {||})
puts; puts "Method:"  ; call_with_too_many_args(method(:no_arg_method))

# For no good reason that I can see, Proc.new, proc and lambda treat a single argument as a special
# case; only a method enforces arity in all cases. Principle of least surprise my ass.
# 没办法解释你和我看到的结果,Proc.new,proc和lambda在面对一个参数时有特殊的处理;
# 只有method在任何情况下都强制执行了参数的个数。真是草尼马的最小惊讶原则。
#
# 注:#example17-19的结果在ruby1.8和1.9下,1.8下proc和lambda的执行结果完全一样,1.9下proc和Proc.new的结果完全相同。


# ---------------------------- Section 5: Rant ----------------------------
# ------------------------------ 章节五:咆哮 -----------------------------
#
# This is quite a dizzing array of syntactic options, with subtle semantics differences that are not
# at all obvious, and riddled with minor special cases. It's like a big bear trap from programmers who
# expect the language to just work.
# 真是让人蛋疼的语法,这些语法上的微妙差异不是那么显而易见的,而且还有不少小的特殊情况。
#
#
# Why are things this way? Because Ruby is:
# 为什么会这样呢?因为ruby是:
#
#   (1) designed by implementation, and
#   (2) defined by implementation.
#   通过实现来设计和定义 (看不明白
#
# The language grows because the Ruby team tacks on cool ideas, without maintaining a real spec apart
# from CRuby. A spec would make clear the logical structure of the language, and thus help highlight
# inconsistencies like the ones we've just seen. Instead, these inconsinstencies creep into the language,
# confuse the crap out of poor souls like me who are trying to learn it, and then get submitted as bug
# reports. Something as fundamental as the semantics of proc should not get so screwed up that they have
# to backtrack between releases, for heaven's sake! Yes, I know, language design is hard -- but something
# like this proc/lambda issue or the arity problem wasn't so hard to get right the first time.
# Yammer yammer.
# (此处省略原作者抱怨的100字。。。)


# ---------------------------- Section 6: Summary ----------------------------
# ------------------------------- 章节六:总结 -------------------------------
#
# So, what's the final verdict on those 7 closure-like entities?          
# 所以,那7个闭包风格的实体最终结论如下:
#
#                                                     "return" returns from closure
#                                    True closure?    or declaring context...?         Arity check?
#                                    ---------------  -----------------------------    -------------------
# 1. block (called with yield)       N                declaring                        no
# 2. block (&b => f(&b) => yield)    N                declaring                        no
# 3. block (&b => b.call)            Y except return  declaring                        warn on too few
# 4. Proc.new                        Y except return  declaring                        warn on too few
# 5. proc                                    <<< alias for lambda in 1.8, Proc.new in 1.9 >>>
# 6. lambda                          Y                closure                          yes, except arity 1
# 7. method                          Y                closure                          yes
#
# The things within each of these groups are all semantically identical -- that is, they're different
# syntaxes for the same thing:
# 下面的分组中的每个在语义上都是相同的,也就是说,只是语法不同的同一个东西。
#   
#      1. block (called with yield)
#      2. block (&b  =>  f(&b)  =>  yield)  
#      -------
#      3. block (&b  =>  b.call)
#      4. Proc.new  
#      5. proc in 1.9
#      -------
#      5. proc in 1.8
#      6. lambda    
#      -------
#      7. method (may be identical to lambda with changes to arity checking in 1.9) 在1.9中参数检查和lambda一样
#
# Or at least, this is how I *think* it is, based on experiment. There's no authoritative answer other
# than testing the CRuby implementation, because there's no real spec -- so there may be other differences
# I haven't discovered.
# 至少,根据实验,我是这么认为的。除了测试CRuby实现外,也没有其他的官方答案。因为没有真实的规范--所以也许和我发现的有些不同。
#
# The final verdict: Ruby has four types of closures and near-closures, expressible in seven syntactic
# variants. Not pretty. But you sure sure do cool stuff with them! That's up next....
# 最终结论:Ruby有四个类型的闭包和近似闭包,使用7中语法变形来体现,不是很好,但是你能他们来做一些很cool的东西。
#
# This concludes the "Ruby sucks" portion of our broadcast; from here on, it will be the "Ruby is
# awesome" portion.


# ---------------------------- Section 7: Doing Something Cool with Closures ----------------------------
# ----------------------------------- 章节七:用闭包来做些Cool的东西 ------------------------------------

# Let's make a data structure containing all of the Fibonacci numbers. Yes, I said *all* of them.
# How is this possible? We'll use closures to do lazy evaluation, so that the computer only calculates
# as much of the list as we ask for.
# 我们创建一个数据结构包含所有的菲波那契数。是的,我说“所有的”。
# 这怎么可能?我们将使用闭包来做到延迟求值,所以计算机仅仅会计算我们所要的。

# To make this work, we're going to use Lisp-style lists: a list is a recursive data structure with
# two parts: "car," the next element of the list, and "cdr," the remainder of the list.
# 要让他工作,我们要使用Lisp风格的lists:一个包含2部分的可递归的数据结构:“car”,list中的下一个元素,“cdr”,list中剩余的元素。
#
# For example, the list of the first three positive integers is [1,[2,[3]]]. Why? Because:
#
#   [1,[2,[3]]]     <--- car=1, cdr=[2,[3]]
#      [2,[3]]      <--- car=2, cdr=[3]
#         [3]       <--- car=3, cdr=nil
#
# Here's a class for traversing such lists:
# 这有一个类来遍历这样的list

example 20

class LispyEnumerable
	include Enumerable

	def initialize(tree)
		@tree = tree
	end

	def each
		while @tree
			car,cdr = @tree
			yield car
			@tree = cdr
		end
	end
end

list = [1,[2,[3]]]
LispyEnumerable.new(list).each do |x|
	puts x
end

# So how to make an infinite list? Instead of making each node in the list a fully built
# data structure, we'll make it a closure -- and then we won't call that closure
# until we actually need the value. This applies recursively: the top of the tree is a closure,
# and its cdr is a closure, and the cdr's cdr is a closure....
# 所以如和去创建一个无限的list?我们通过创建一个闭包来代替原来在list中内建的基本数据结构。
# 除非我们真得须要数据,否则我们不会调用它。它会是一个递归。。。

example 21

class LazyLispyEnumerable
	include Enumerable

	def initialize(tree)
		@tree = tree
	end

	def each
		while @tree
			car,cdr = @tree.call # <--- @tree is a closure
			yield car
			@tree = cdr
		end
	end
end

list = lambda{[1, lambda {[2, lambda {[3]}]}]} # same as above, except we wrap each level in a lambda 和前面的一样,只是多包了一个lambda
LazyLispyEnumerable.new(list).each do |x|
	puts x
end

example 22

# Let's see when each of those blocks gets called:
# 让我们来看看这些block是什么时候被调用的
list = lambda do
	puts "first lambda called"
	[1, lambda do
		puts "second lambda called"
		[2, lambda do
			puts "third lambda called"
			[3]
		end]
	end]
end

puts "List created; about to iterate:"
LazyLispyEnumerable.new(list).each do |x|
	puts x
end


# Now, because the lambda defers evaluation, we can make an infinite list:
# 现在,因为lamdba的延迟求值,我们可以创建无限list。

example 23

def fibo(a,b)
	lambda { [a, fibo(b,a+b)] } # <---- this would go into infinite recursion if it weren't in a lambda 这个会进入死循环如果它不在lambda内部
end

LazyLispyEnumerable.new(fibo(1,1)).each do |x|
	puts x
	break if x > 100 # we don't actually want to print all of the Fibonaccis! 我们实际上不会要打印所有的菲波那契数。
end

# This kind of deferred execution is called "lazy evaluation" -- as opposed to the "eager
# evaluation" we're used to, where we evaluate an expression before passing its value on.
# (Most languages, including Ruby, use eager evaluation, but there are languages (like Haskell)
# which use lazy evaluation for everything, by default! Not always performant, but ever so very cool.)
# 这就是延迟求值,和我们通常用得立即求值相反,我们在传送值之前就求值了表达式。
# 大部分语言,包括ruby,都是立即求值,但是有些其他语言,比如Haskell,他默认就是对任何都延迟求值。
# 这不是一直是高性能的,但是这非常cool。
#
# This way of implementing lazy evaluation is terribly clunky! We had to write a separate
# LazyLispyEnumerable that *knows* we're passing it a special lazy data structure. How unsatisfying!
# Wouldn't it be nice of the lazy evaluation were invisible to callers of the lazy object?
# 这种实现延迟求值的方式是非常笨拙的。我们不得不写一个单独的LazyLispyEnumerable,让他知道我们传了一个
# 特别的延迟数据结构给他。能不能让他更好的处理延迟求值,让他对于调用者隐藏延迟对象?
#
# As it turns out, we can do this. We'll define a class called "Lazy," which takes a block, turns it
# into a closure, and holds onto it without immediately calling it. The first time somebody calls a
# method, we evaluate the closure and then forward the method call on to the closure's result.
# 事实证明,我们可以这么做。我们定一个叫“Lazy”的类,然后使用block,把它转成闭包,然后保存它。
# 第一次一些人调用了它,我们求取闭包的值,然后跳转到下一个方法调用。

class Lazy
	def initialize(&generator)
		@generator = generator
	end

	def method_missing(method, *args, &block)
		evaluate.send(method, *args, &block)
	end

	def evaluate
		@value = @generator.call unless @value
		@value
	end
end

def lazy(&b)
	Lazy.new &b
end

# This basically allows us to say:
# 你可以这样来使用:
#
#   lazy {value}
# 
# ...and get an object that *looks* exactly like value -- except that value won't be created until the
# first method call that touches it. It creates a transparent lazy proxy object. Observe:
# 。。。然后就能得到一个看起来像指定的value一样的对象—— 除了value只有在一次调用method的以后才会创建。
# 它创建了一个透明的延迟代理对象。

example 24

x = lazy do
	puts "<<< Evaluating lazy value >>>"
	"lazy value"
end

puts "x has now been assigned"
puts "About to call one of x's methods:"
puts "x.size: #{x.size}"          # <--- .size triggers lazy evaluation .size会触发延迟求值
puts "x.swapcase: #{x.swapcase}"

# So now, if we define fibo using lazy instead of lambda, it should magically work with our
# original LispyEnumerable -- which has no idea it's dealing with a lazy value! Right?
# 现在,我们使用lazy代替lambda来创建菲波那契函数,它应该可以神奇地和我们来原的LispyEnumerable工作。
# LispyEnumerable并不知道如何处理一个lazy value!是不是?

example 25

def fibo(a,b)
	lazy { [a, fibo(b,a+b)] }
end

LispyEnumerable.new(fibo(1,1)).each do |x|
	puts x
	break if x.instance_of?(Lazy) || x > 200
end

# 这个方法在ruby 1.8和1.9中不一样
# 1.8中会调用respond_to?(to_a)方法来找to_a,而respond_to又是Object的方法,每个对象都会有,所以不会经过method_missing
# 1.9中会直接调用method_missing(to_a)方法来找to_a
# 所以1.8只会打印出一个Lazy对象,而1.9中可以顺利执行

# Oops! That didn't work. What went wrong?
# 噢,它并没有如我们想的那样工作,哪里出错了?
#
# The failure started in this line of LispyEnumerable (though Ruby didn't report the error there):
# 错误发生在LispyEnumerable的这一行(尽管Ruby没有报错)
#
#      car,cdr = @tree
#
# Let's zoom in on that result, and see what happened:
# 让我们看看到底发生了什么!

example 26

car,cdr = fibo(1,1)
puts "car=#{car}  cdr=#{cdr}"

# Here's the problem. When we do this:
# 问题就在这里,当我们这样赋值时:
#
#   x,y = z
#
# ...Ruby calls z.respond_to?(to_a) to see if z is an array. If it is, it will do the multiple
# assignment; if not, it will just assign x=z and set y=nil.
# Ruby会调用z.respond_to?(to_a)来看看z是否能变成一个数组。如果可以,它会进行多次赋值,
# 否则,它只会赋值 x=z 和 y = nil。
#
# We want our Lazy to forward the respond_to? call to our fibo list. But it doesn't forward it,
# because we used the method_missing to do the proxying -- and every object implements respond_to?
# by default, so the method isn't missing! The respond_to? doesn't get forwarded; instead, out Lazy
# says "No, I don't respond to to_a; thanks for asking." The immediate solution is to forward
# respond_to? manually:
# 我们想要的Lazy来转发respond_to?,让它调用到我们的菲波那契。但是它没有做到,因为我们用method_missing
# 来进行代理 -- 而每个对象默认都有respond_to?方法,所以无法触发到method_missing!respond_to?方法没有被转发,
# 所以Lazy说:“我没有to_a方法,谢谢你的调用。”最快捷的办法是手动转发respond_to?方法。

class Lazy
	def initialize(&generator)
		@generator = generator
	end

	def method_missing(method, *args, &block)
		evaluate.send(method, *args, &block)
	end

	def respond_to?(method)
		evaluate.respond_to?(method)
	end

	def evaluate
		@value = @generator.call unless @value
		@value
	end
end

# And *now* our original Lispy enum can work:
# 现在我们原来的Lispy enum就能工作了。

example 27

LispyEnumerable.new(fibo(1,1)).each do |x|
	puts x
	break if x > 200
end

# Of course, this only fixes the problem for respond_to?, and we have the same problem for every other
# method of Object. There is a more robust solution -- frightening, but it works -- which is to undefine
# all the methods of the Lazy when it's created, so that everything gets forwarded.
# 当然,这只是修改了respond_to?的问题,Object的其他方法也有同样的问题。这里有一个更健壮的办法,虽然有点可怕,
# 但是它能工作。那就是在Lazy对象创建时取消定义Lazy所有的方法,那样就都能被转发了。
#
# And guess what? There's already a slick little gem that will do it:
# 其实已经有一个gem做了这样的事:
#
#     http://moonbase.rydia.net/software/lazy.rb/
#
# Read the source. It's fascinating.
# 看看它的源码把,非常让人着迷。

# ---------------------------- Section 8: Wrap-Up ----------------------------
# ------------------------------- 章节八:总结 -------------------------------

# So sure, this was all entertaining -- but is it good for anything?
# 这就是所有了 -- 那么是不是它有利于任何事?
#
# Well, suppose you have an object which requires a network or database call to be created, or will
# use a lot of memory once it exists. And suppose that it may or may not be used, but you don't know
# at the time it's created whether it will be. Making it lazy will prevent it from consuming resources
# unless it needs to. Hibernate does this to prevent unnecessary DB queries, and it does it with more or
# less arbitrary Java objects (i.e. unlike ActiveRecord, it doesn't depend on a base class to do its
# lazy loading). Ruby can do the same thing, but with a lot less code!
# 假设你有一个对象须要一个网络或者数据库的调用才能被创建,或者会一旦创建会占用大量内存。你也不知道什么
# 时候会用到它。使用lazy将防止它消耗资源,除非它真得需要。Hibernate使用延迟加载来阻止不必要的数据库查询,
# 而Hibernate做到它需要或多或少的Java对象。(不像ActiveRecord,它依赖于一个base class来做到延迟加载)
# Ruby可以使用更少的代码做到相同的事情。
#
#
# That's just an example. Use your imagination.
# 这只是个示例,发挥你的想象力。
#
# If you're a functional langauge geek, and enjoyed seeing Ruby play with these ideas from Lisp and
# Haskell, you may enjoy this thread:
# 如果你是个函数式语言的极客,并且喜欢使用Ruby的这些来自于Lisp和Haskell的特性,你也许会想加入
#
#     http://redhanded.hobix.com/inspect/curryingWithArity.html
#
# OK, I'll stop making your brain hurt now. Hope this has been a bit enlightening! The experience
# of working it out certainly was for me.
# 好了,我不再伤害你的大脑了。希望这能够给你一点启发!理解这些的经验对我非常有用。
#
# Paul